sc-file 0.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. sc_file-0.0.0.dist-info/METADATA +140 -0
  2. sc_file-0.0.0.dist-info/RECORD +84 -0
  3. sc_file-0.0.0.dist-info/WHEEL +5 -0
  4. sc_file-0.0.0.dist-info/entry_points.txt +2 -0
  5. sc_file-0.0.0.dist-info/licenses/LICENSE +21 -0
  6. sc_file-0.0.0.dist-info/top_level.txt +1 -0
  7. scfile/__init__.py +19 -0
  8. scfile/__main__.py +26 -0
  9. scfile/cli/__init__.py +13 -0
  10. scfile/cli/commands.py +121 -0
  11. scfile/cli/types.py +21 -0
  12. scfile/cli/utils.py +62 -0
  13. scfile/consts.py +106 -0
  14. scfile/convert/__init__.py +33 -0
  15. scfile/convert/base.py +65 -0
  16. scfile/convert/detect.py +89 -0
  17. scfile/convert/factory.py +38 -0
  18. scfile/convert/formats.py +163 -0
  19. scfile/convert/legacy.py +87 -0
  20. scfile/core/__init__.py +29 -0
  21. scfile/core/base.py +20 -0
  22. scfile/core/context/__init__.py +16 -0
  23. scfile/core/context/content.py +92 -0
  24. scfile/core/context/options.py +24 -0
  25. scfile/core/decoder.py +104 -0
  26. scfile/core/encoder.py +111 -0
  27. scfile/core/io/__init__.py +13 -0
  28. scfile/core/io/base.py +55 -0
  29. scfile/core/io/streams.py +39 -0
  30. scfile/core/types.py +14 -0
  31. scfile/enums.py +119 -0
  32. scfile/exceptions.py +109 -0
  33. scfile/formats/__init__.py +22 -0
  34. scfile/formats/dae/__init__.py +4 -0
  35. scfile/formats/dae/encoder.py +218 -0
  36. scfile/formats/dae/utils.py +38 -0
  37. scfile/formats/dds/__init__.py +4 -0
  38. scfile/formats/dds/encoder.py +99 -0
  39. scfile/formats/dds/enums.py +40 -0
  40. scfile/formats/dds/header.py +26 -0
  41. scfile/formats/dds/mask.py +12 -0
  42. scfile/formats/glb/__init__.py +4 -0
  43. scfile/formats/glb/base.py +26 -0
  44. scfile/formats/glb/encoder.py +339 -0
  45. scfile/formats/glb/enums.py +17 -0
  46. scfile/formats/hdri/__init__.py +4 -0
  47. scfile/formats/hdri/decoder.py +27 -0
  48. scfile/formats/mcsa/__init__.py +9 -0
  49. scfile/formats/mcsa/decoder.py +242 -0
  50. scfile/formats/mcsa/exceptions.py +47 -0
  51. scfile/formats/mcsa/io.py +129 -0
  52. scfile/formats/mcsa/versions.py +14 -0
  53. scfile/formats/mcsb/__init__.py +4 -0
  54. scfile/formats/mcsb/decoder.py +11 -0
  55. scfile/formats/mic/__init__.py +4 -0
  56. scfile/formats/mic/decoder.py +17 -0
  57. scfile/formats/ms3d/__init__.py +8 -0
  58. scfile/formats/ms3d/encoder.py +140 -0
  59. scfile/formats/ms3d/exceptions.py +23 -0
  60. scfile/formats/ms3d/io.py +18 -0
  61. scfile/formats/obj/__init__.py +4 -0
  62. scfile/formats/obj/encoder.py +67 -0
  63. scfile/formats/obj/faces.py +17 -0
  64. scfile/formats/ol/__init__.py +9 -0
  65. scfile/formats/ol/decoder.py +71 -0
  66. scfile/formats/ol/exceptions.py +21 -0
  67. scfile/formats/ol/formats.py +9 -0
  68. scfile/formats/ol/io.py +22 -0
  69. scfile/formats/png/__init__.py +4 -0
  70. scfile/formats/png/encoder.py +12 -0
  71. scfile/formats/texarr/__init__.py +4 -0
  72. scfile/formats/texarr/decoder.py +30 -0
  73. scfile/formats/zip/__init__.py +4 -0
  74. scfile/formats/zip/encoder.py +13 -0
  75. scfile/structures/__init__.py +16 -0
  76. scfile/structures/animation.py +35 -0
  77. scfile/structures/flags.py +18 -0
  78. scfile/structures/mesh.py +55 -0
  79. scfile/structures/scene.py +77 -0
  80. scfile/structures/skeleton.py +122 -0
  81. scfile/structures/texture.py +57 -0
  82. scfile/structures/types.py +6 -0
  83. scfile/structures/vectors.py +18 -0
  84. scfile/types.py +7 -0
@@ -0,0 +1,140 @@
1
+ Metadata-Version: 2.4
2
+ Name: sc-file
3
+ Version: 0.0.0
4
+ Summary: Utility & Library for decoding stalcraft assets
5
+ Author-email: onejeuu <mail@66rk.ru>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/onejeuu/sc-file
8
+ Project-URL: Repository, https://github.com/onejeuu/sc-file
9
+ Project-URL: Documentation, https://sc-file.readthedocs.io
10
+ Requires-Python: >=3.11
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: click<9.0.0,>=8.2.0
14
+ Requires-Dist: lz4<5.0.0,>=4.4.0
15
+ Requires-Dist: numpy<3.0.0,>=2.3.0
16
+ Requires-Dist: rich<15.0.0,>=14.1.0
17
+ Dynamic: license-file
18
+
19
+ # sc-file
20
+
21
+ <!-- Links -->
22
+
23
+ [pypi]: https://pypi.org/project/sc-file
24
+ [license]: https://opensource.org/licenses/MIT
25
+ [tests]: https://github.com/onejeuu/sc-file/actions/workflows/tests.yml
26
+ [build]: https://github.com/onejeuu/sc-file/actions/workflows/release.yml
27
+ [issues]: https://github.com/onejeuu/sc-file/issues
28
+ [releases]: https://github.com/onejeuu/sc-file/releases
29
+ [docs]: https://sc-file.readthedocs.io/en/latest
30
+ [readme-ru]: README-RU.md
31
+
32
+ <!-- Usage -->
33
+
34
+ [usage-dragndrop]: https://en.wikipedia.org/wiki/Drag_and_drop
35
+ [usage-defaultapp]: https://support.microsoft.com/en-us/windows/e5d82cad-17d1-c53b-3505-f10a32e1894d
36
+ [usage-cli]: https://en.wikipedia.org/wiki/Command-line_interface
37
+ [usage-library]: https://pypi.org/project/sc-file
38
+
39
+ <!-- Docs -->
40
+
41
+ [docs-usage]: https://sc-file.readthedocs.io/en/latest/usage.html
42
+ [docs-faq]: https://sc-file.readthedocs.io/en/latest/faq.html
43
+ [docs-formats]: https://sc-file.readthedocs.io/en/latest/formats.html
44
+ [docs-support]: https://sc-file.readthedocs.io/en/latest/support.html
45
+ [docs-compile]: https://sc-file.readthedocs.io/en/latest/compile.html
46
+ [docs-library]: https://sc-file.readthedocs.io/en/latest/api/index.html
47
+
48
+ <!-- Badges -->
49
+
50
+ [badge-pypi]: https://img.shields.io/pypi/v/sc-file.svg
51
+ [badge-license]: https://img.shields.io/github/license/onejeuu/sc-file
52
+ [badge-docs]: https://img.shields.io/readthedocs/sc-file
53
+ [badge-tests]: https://img.shields.io/github/actions/workflow/status/onejeuu/sc-file/tests.yml?label=tests
54
+ [badge-build]: https://img.shields.io/github/actions/workflow/status/onejeuu/sc-file/release.yml?label=build
55
+ [badge-issues]: https://img.shields.io/github/issues/onejeuu/sc-file
56
+ [badge-ru]: https://img.shields.io/badge/перевод%20на-🇷🇺%20Русский-0096FF
57
+
58
+ <img src="assets/scfile.svg" alt="icon" width="96" />
59
+
60
+ [![Pypi][badge-pypi]][pypi] [![License][badge-license]][license] [![Docs][badge-docs]][docs] [![Tests][badge-tests]][tests] [![Build][badge-build]][build] [![Issues][badge-issues]][issues]
61
+
62
+ [![RU][badge-ru]][readme-ru]
63
+
64
+ ## Overview
65
+
66
+ **scfile** is a utility and library for converting stalcraft assets (such as models and textures), into standard formats.
67
+
68
+ _this project is unofficial and not related to stalcraft devs. all trademarks and assets belong to their respective owners._
69
+
70
+ 📚 Documentation: [sc-file.readthedocs.io][docs] \
71
+ [Usage][docs-usage] / [FAQ][docs-faq] / [Game Formats][docs-formats] / [Formats Support][docs-support] / [Compile Guide][docs-compile] / [Library API Reference][docs-library]
72
+
73
+ 🗂️ Supported game formats: `.mcsb`, `.mcsa`, `.mcvd`, `.ol`, `.mic`, `.texarr`. \
74
+ [More about Game Formats...][docs-formats]
75
+
76
+ 💻 Executable utility `scfile.exe` can be downloaded from [Releases page][releases] or [compiled from source][docs-compile] \
77
+ [More about Usage...][docs-usage]
78
+
79
+ ❓ **Why reverse encoding into game formats is unsupported?** \
80
+ And other common questions are answered on [FAQ page][docs-faq].
81
+
82
+ ## 🛠️ Supported Formats
83
+
84
+ | Type | Source | Output |
85
+ | ---------- | ------------------------- | ------------------------------- |
86
+ | 🧊 Model | `.mcsb`, `.mcsa`, `.mcvd` | `.glb`, `.obj`, `.dae`, `.ms3d` |
87
+ | 🧱 Texture | `.ol` | `.dds` |
88
+ | 🖼️ Image | `.mic` | `.png` |
89
+ | 📦 Archive | `.texarr` | `.zip` |
90
+
91
+ [More about Formats Support…][docs-support]
92
+
93
+ ## 🚀 Usage
94
+
95
+ - **Easiest way is [Drag & Drop][usage-dragndrop]**. Just drag and drop your files onto `scfile.exe`.
96
+ - **Set scfile.exe as the [default application][usage-defaultapp]** for the required file types.
97
+ - **Via terminal as [CLI][usage-cli]** for specifying parameters.
98
+ - **As [Python library][usage-library]** for complex tasks.
99
+
100
+ Command example:
101
+
102
+ ```bash
103
+ scfile.exe model.mcsb -F dae --skeleton
104
+ ```
105
+
106
+ [More about Usage...][docs-usage]
107
+
108
+ ## 📖 Library
109
+
110
+ To install library for coding, use following command:
111
+
112
+ ```bash
113
+ pip install sc-file -U
114
+ ```
115
+
116
+ Simple usage example:
117
+
118
+ ```python
119
+ from scfile import UserOptions, convert
120
+
121
+ # Optional convert settings
122
+ options = UserOptions(parse_skeleton=True)
123
+
124
+ # Specific format to format
125
+ convert.mcsb_to_obj(source="path/to/model.mcsb", options=options)
126
+
127
+ # Or auto detect by file suffix
128
+ convert.auto(source="path/to/model.mcsb", options=options)
129
+ ```
130
+
131
+ [More details about Library...][docs-library]
132
+
133
+ ## 🤝 Acknowledgments
134
+
135
+ - `kommunist2021` – file structure research.
136
+ - `Art3mLapa` – advice, bug reports, contribution.
137
+ - `n1kodim` – advice, contribution.
138
+ - `IExploitableMan` – contribution.
139
+ - `Sarioga` – feedback, bug reports.
140
+ - `Hazart` – bug reports.
@@ -0,0 +1,84 @@
1
+ sc_file-0.0.0.dist-info/licenses/LICENSE,sha256=F-SU1JkdAgWCldOJezvXupiEtyofFUZhFevinEqdQTo,1063
2
+ scfile/__init__.py,sha256=MCDk6nVxa211blNWq15tR3WEJNV1Cf7Y7bYWnwAdQWc,344
3
+ scfile/__main__.py,sha256=EGR9PD2JwK30qyTohMFXwgpgRwvwmsKyVekVTizO2SQ,434
4
+ scfile/consts.py,sha256=1ktWs52kOlmZhGQ5ZJ_BrftruwjOwoeaTzIW0x5mzPE,2342
5
+ scfile/enums.py,sha256=pjonOtCA-qqRz6kFrH8UXPVEoSjmFKCxlS827bVh6GY,2585
6
+ scfile/exceptions.py,sha256=TShI27nBTo2YVNeNZHNEdwmr0HvZihtWpfdcXFiykiY,2399
7
+ scfile/types.py,sha256=3fVn8J04gQSBtoVaPvMRImUzslFmdlFXAu3yB5Eyhak,168
8
+ scfile/cli/__init__.py,sha256=4KrjuD5K4z4b9stkOdQXR8g4TdD0fDPRjDZCE_yxLBI,207
9
+ scfile/cli/commands.py,sha256=tXT_GRtyb_AAxHipvGQjy1cUbkwCtaa5crfpGEoalt0,3283
10
+ scfile/cli/types.py,sha256=Y_hVj19pqoBUtTBWsDSJqRkz__OA0GPqZVNATn6mGrY,592
11
+ scfile/cli/utils.py,sha256=5-3p_V5YPr3SI47XFYVwGVT4XH7mq7H81L-jMoAKzuc,1997
12
+ scfile/convert/__init__.py,sha256=ug0Ina7K6w8efkgrrbBfUbdtlbXmpTksgXzagmUVQZw,544
13
+ scfile/convert/base.py,sha256=SQG5TSNEB7CJ-7zoT9lkP7uvInyAxmkZ2jxX0XBR3oE,1889
14
+ scfile/convert/detect.py,sha256=Ux5w4Z_UKqiWqt3k4NFT3AKnXxYvm4Nejvvtp3ak5FI,2599
15
+ scfile/convert/factory.py,sha256=jUuqqiova-j8kg7-THJpwENhPXoUMSd4xGGmTtIqQQI,948
16
+ scfile/convert/formats.py,sha256=C6jd0Cxj4ndGbJ2IbA85raMo8zZHIOS50OKSTmmRavI,4674
17
+ scfile/convert/legacy.py,sha256=7iSp1_UrWYdSx5RK7B0JjoGOftZgd9z3BiOE-Ge0L7M,2514
18
+ scfile/core/__init__.py,sha256=nieAAh9IsHE-zh28CSIxvT7EmcotpUEb9rtzqm8prpk,653
19
+ scfile/core/base.py,sha256=vjN4aGENOc-AeBDzYYSVVQ9DrmuJ-g5j75KWxjsIl00,423
20
+ scfile/core/decoder.py,sha256=yOGRrJTPZBwC0FGdaVaTjl9oYKGx4Ce4xP5WHAS4g5Q,3414
21
+ scfile/core/encoder.py,sha256=N_cd5lnL1Y0SyPmE0v2XhdtHB7aTM4IpOwADT-q4lIk,3708
22
+ scfile/core/types.py,sha256=-F-KNz9dCX3Bzd1vvwJ5xUchz9Oe0Cooy2VuFnjVtCA,231
23
+ scfile/core/context/__init__.py,sha256=t8xPwyOGbtj0IGKwAvS3MK1ZV7-Ke2_5V7FzCXH4LW8,327
24
+ scfile/core/context/content.py,sha256=P28JflRZmkDWQYSDClZNwnqCY4nXKF_mWw5JoRYml8g,2415
25
+ scfile/core/context/options.py,sha256=j-JqoUUG24z-8BshjZfcDpdyN5rw-4xiLw94S4e1DKM,582
26
+ scfile/core/io/__init__.py,sha256=5D0kPshJC7MQ_ocNrltGX5-cJNfWhyDbnSoqYZY-S8k,259
27
+ scfile/core/io/base.py,sha256=bwRW_V-RAGG4Jsr8YaPZsBK30q31EZFkmW8EVHdePXc,1817
28
+ scfile/core/io/streams.py,sha256=bvZFMLD1M6pNKAEtaUksY0vj4W_8okJ3UwxOLgLgLtE,859
29
+ scfile/formats/__init__.py,sha256=pF9uRnWnYKMAqHHoOE0TSDT7LILqtMqeRRHM_b8qff0,336
30
+ scfile/formats/dae/__init__.py,sha256=Zj8367IuQC4Y_PkD70ChtOHXqgY6I9KiUK0Eqgmb7jo,60
31
+ scfile/formats/dae/encoder.py,sha256=MWdpnF3mltuo1BE3q3NQm6myykfDBi7Wrb6KClIiU7A,9114
32
+ scfile/formats/dae/utils.py,sha256=OwtvZqMtWBFQ8owpHJ25INFpAfievvViopf1pffOWEE,1025
33
+ scfile/formats/dds/__init__.py,sha256=H8TNV4n5vwu_0wjrW6lrCjMZsmxrFPoEXKQWxRDkR48,60
34
+ scfile/formats/dds/encoder.py,sha256=Lu-JR9YtniJfnRNV_ic5NWVpwknmFRTavEcOhTqPlPw,3029
35
+ scfile/formats/dds/enums.py,sha256=bVKCxnGo40AWwyTtwZZadglAb0SSKXP4gAlBZQFoLtI,714
36
+ scfile/formats/dds/header.py,sha256=MBURWS7ZB9bvV8BSdFFa-9qW9aByjp4k8XywczVUyWY,597
37
+ scfile/formats/dds/mask.py,sha256=zANIwEaknx1yPwJvexSbfwEzu2tyUK460Agbm7nAQvk,191
38
+ scfile/formats/glb/__init__.py,sha256=rpBTrL6D7WisNLmMJwbfSu8qjNKdbq5hRaUUIzJates,59
39
+ scfile/formats/glb/base.py,sha256=db15BqAOTDkoUqkLJSi-pQLCMucyJgXQcj7EpOLLNkQ,502
40
+ scfile/formats/glb/encoder.py,sha256=1dN8269-1bDu_88F_otywu36DYTovtjMtbjx8vYpMuA,11641
41
+ scfile/formats/glb/enums.py,sha256=OQDemwFndPXDg5qPgeAxiX92t8__a0xhqs6KebDGw4o,266
42
+ scfile/formats/hdri/__init__.py,sha256=zz3wmS8vC_3oe5tTXAbhy-HN1LpdAOM_U_LVXQV3Vw0,71
43
+ scfile/formats/hdri/decoder.py,sha256=GGJorFcDW4bD1v8AAICU9MN7_02M5M8HzfkpPmLI2ME,980
44
+ scfile/formats/mcsa/__init__.py,sha256=1zMzLORm22YxsNRoJ2_QmbIfGyU9bRWEzvOwHYLR1QA,137
45
+ scfile/formats/mcsa/decoder.py,sha256=X-ew_hiqSDvLkHq6W7MBZ0UzRoX4YdyVqAujPu4vh3Q,7655
46
+ scfile/formats/mcsa/exceptions.py,sha256=gAjvioHn73H7AsVBACs2KKhLct6n9zQFokdwnmkEflY,1278
47
+ scfile/formats/mcsa/io.py,sha256=qCoNLSt4VvwG9fM5OiZaAUh2-pxPTiwDofwQfsoionc,3909
48
+ scfile/formats/mcsa/versions.py,sha256=jXoRrH51rbHXeTR6fWq17eQM5h3dB9ubAR3hXDXluXc,248
49
+ scfile/formats/mcsb/__init__.py,sha256=--ygCGNmZlxvxFUrzaECvDRE_yOLyTx3nAMd6PfKDlQ,61
50
+ scfile/formats/mcsb/decoder.py,sha256=WwcoNMh1oqF0BOnPuifGooQ9oU5Q4rnSjtbVsrAktgA,287
51
+ scfile/formats/mic/__init__.py,sha256=ipmhCnAXiSrGRFXU1LgS_i5A3ON3s3k6YrSEh-Ar2fo,59
52
+ scfile/formats/mic/decoder.py,sha256=bTwQtoeTknueDU4C0IT3suTt-HnP6CkfW5BSlpzGKfQ,448
53
+ scfile/formats/ms3d/__init__.py,sha256=JzlJlzW81MOgt2HHU68D9NYmJZ_zJE4fdxhd5ubnncc,111
54
+ scfile/formats/ms3d/encoder.py,sha256=DY9tKMNhEBlmuCKGjQCuGU6JZEp4viOR-Wk5gktdntY,5043
55
+ scfile/formats/ms3d/exceptions.py,sha256=68B8Mz5z0SvQ0vVgLw4GrKX3UMbV4SlmRnIypu9AYWE,584
56
+ scfile/formats/ms3d/io.py,sha256=rqrDzCZWI43Um2DEatcKKKPMw_K2kp_MvZXO5Lx8IFc,521
57
+ scfile/formats/obj/__init__.py,sha256=v7COYPO0-Y8iKpSG8-0Il_mlsjuwJgucuQt469tTD1s,59
58
+ scfile/formats/obj/encoder.py,sha256=qGPruV8SxSgyv431xhuSWJWPRGDZa0PTDTw2JsZ6TUQ,2202
59
+ scfile/formats/obj/faces.py,sha256=VC-2Ogy50FaGJXe2TcgH8KCyetZj8viyz4c_d__tSzg,426
60
+ scfile/formats/ol/__init__.py,sha256=UmXOuoT8NcfAVFEPSv5imHc468O8LmD-mAW6BAQvD-U,131
61
+ scfile/formats/ol/decoder.py,sha256=XEqWEX11ZG8F8rUfVBNX_fI4EkG-aerB_hr1FA-LZzg,2092
62
+ scfile/formats/ol/exceptions.py,sha256=In-XAO_p9wjvaB1Vn1LtML7CUq7QD8qJK93mRzBPwxw,520
63
+ scfile/formats/ol/formats.py,sha256=fjujvTX6Bygyiob1JyweBL6NUjzdX65j9IGhB38C14k,135
64
+ scfile/formats/ol/io.py,sha256=bCliJj3W9MJDstq8iHbpWL_HQk8Dj74wVO-up1BRyvA,778
65
+ scfile/formats/png/__init__.py,sha256=Ii9Y88llmEOV02fDyE7iAus20vmHCqnD00wnYFQsVBI,59
66
+ scfile/formats/png/encoder.py,sha256=gM6a9-5QSt4hfFD3A3TryHO_FidEMDTlhwQBmgHfeqg,328
67
+ scfile/formats/texarr/__init__.py,sha256=Ky1NS8dYS5BTDIsJbClmQXJ5CN9JrTDYfKnaH7w8wcY,78
68
+ scfile/formats/texarr/decoder.py,sha256=_tXJ1WnuxqUbU2-YW035fU6TTqgRZBiyyS0nX3MGKtM,805
69
+ scfile/formats/zip/__init__.py,sha256=NcgrNWy_Rnek7de1VFZJADulvVUXg7r_IgwC4yyclWw,78
70
+ scfile/formats/zip/encoder.py,sha256=28OOYrEOjjEL9ah_VkXJ3UW8bk3WNGwfkIw4tI3y1Rs,402
71
+ scfile/structures/__init__.py,sha256=g62_wTCxOF2RDBBeT2KaJJUz6JMKOa69KyufI6z7Thg,279
72
+ scfile/structures/animation.py,sha256=UJ7BmOZ2DQhssUT02D7mI1CVCJQuALV57GLujdr7tEY,853
73
+ scfile/structures/flags.py,sha256=BtZOCm8dFfisy8Z3L9VsiEznVzsCjVikcWa5DD1Ijhc,320
74
+ scfile/structures/mesh.py,sha256=C_o57A9dieixDQRdQWIEcT1WDFhFAJ4Ur_Hc5xeoEmM,1717
75
+ scfile/structures/scene.py,sha256=49hGqjzu0pla2h1jOpfwB30Mh7oE0xuFXLoP0Xcpw1w,1926
76
+ scfile/structures/skeleton.py,sha256=UZa9rRfNmTWQQ8WkbmdYFhGCnyTJN_PQjRaoLBnCHk4,3643
77
+ scfile/structures/texture.py,sha256=S6ZEd1yc560pKAy1okkw3VW8Dw8FhP2VX1xCFZ318So,1325
78
+ scfile/structures/types.py,sha256=QwEcIuQUXj_9gTCbOArAmruZUqjUNZe5WnZHLD7KVKQ,128
79
+ scfile/structures/vectors.py,sha256=613afYk14VS51WOOXGDC9Oo0esBowSirak7e6FWR8PI,434
80
+ sc_file-0.0.0.dist-info/METADATA,sha256=hXTcXINXfPA2mLJty0idlc8Im8xF4qdpol19G2enC_M,5294
81
+ sc_file-0.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
82
+ sc_file-0.0.0.dist-info/entry_points.txt,sha256=wjcio3iI6X_NoBBAepGm6UGrDnmIXK-KHuJpZ8oMhR0,48
83
+ sc_file-0.0.0.dist-info/top_level.txt,sha256=kD3ZzfXy17HaeDhcENn7dQpnDMufc7CRmoa3DbUHFzo,7
84
+ sc_file-0.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ scfile = scfile.__main__:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 onejeuu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ scfile
scfile/__init__.py ADDED
@@ -0,0 +1,19 @@
1
+ __version__ = "4.1.2"
2
+ __author__ = "onejeuu"
3
+ __license__ = "MIT"
4
+
5
+
6
+ from . import cli, convert, core, exceptions, formats, structures, consts, enums
7
+ from .core.context.options import UserOptions
8
+
9
+ __all__ = (
10
+ "cli",
11
+ "convert",
12
+ "core",
13
+ "exceptions",
14
+ "formats",
15
+ "structures",
16
+ "consts",
17
+ "enums",
18
+ "UserOptions",
19
+ )
scfile/__main__.py ADDED
@@ -0,0 +1,26 @@
1
+ import sys
2
+
3
+ import click
4
+ from rich import print
5
+
6
+ from scfile.cli import scfile
7
+ from scfile.enums import L
8
+
9
+
10
+ def main():
11
+ """Program entrypoint."""
12
+
13
+ try:
14
+ scfile(standalone_mode=False)
15
+
16
+ except click.ClickException as err:
17
+ print(L.INVALID, str(err))
18
+
19
+ except (KeyboardInterrupt, click.exceptions.Abort):
20
+ print("[yellow]Operation aborted.[/]")
21
+
22
+ sys.exit()
23
+
24
+
25
+ if __name__ == "__main__":
26
+ main()
scfile/cli/__init__.py ADDED
@@ -0,0 +1,13 @@
1
+ """
2
+ CLI wrapper module. Responsible for implementation of interaction with internal core.
3
+ """
4
+
5
+ from .commands import scfile
6
+ from . import types, utils
7
+
8
+
9
+ __all__ = (
10
+ "scfile",
11
+ "types",
12
+ "utils",
13
+ )
scfile/cli/commands.py ADDED
@@ -0,0 +1,121 @@
1
+ """
2
+ CLI wrapper implementation.
3
+ """
4
+
5
+ import traceback
6
+ from typing import Optional
7
+
8
+ import click
9
+ from rich import print
10
+
11
+ from scfile import __version__, convert, exceptions
12
+ from scfile.consts import CLI, Formats
13
+ from scfile.core import UserOptions
14
+ from scfile.enums import L
15
+
16
+ from . import types, utils
17
+
18
+
19
+ @click.command(name="scfile", epilog=CLI.EPILOG)
20
+ @click.argument("PATHS", type=types.Files, nargs=-1)
21
+ @click.option(
22
+ "-O",
23
+ "--output",
24
+ help="Output results directory.",
25
+ type=types.Output,
26
+ )
27
+ @click.option(
28
+ "-F",
29
+ "--mdlformat",
30
+ help="Preferred format for models.",
31
+ type=types.Formats,
32
+ multiple=True,
33
+ )
34
+ @click.option(
35
+ "--relative",
36
+ help="Preserve directory structure from source in output.",
37
+ is_flag=True,
38
+ )
39
+ @click.option(
40
+ "--parent",
41
+ help="Use parent directory as starting point in relative directory.",
42
+ is_flag=True,
43
+ )
44
+ @click.option(
45
+ "--skeleton",
46
+ help="Parse armature in models.",
47
+ is_flag=True,
48
+ )
49
+ @click.option(
50
+ "--animation",
51
+ help="Parse builtin clips in models.",
52
+ is_flag=True,
53
+ )
54
+ @click.option(
55
+ "--unique",
56
+ help="Ensure file saved with unique name, avoiding overwrites.",
57
+ is_flag=True,
58
+ )
59
+ @click.version_option(version=__version__)
60
+ @click.pass_context
61
+ def scfile(
62
+ ctx: click.Context,
63
+ paths: types.FilesPaths,
64
+ output: types.OutputDir,
65
+ mdlformat: Optional[Formats],
66
+ relative: bool,
67
+ parent: bool,
68
+ skeleton: bool,
69
+ animation: bool,
70
+ unique: bool,
71
+ ) -> None:
72
+ # In case program executed without arguments
73
+ if not paths:
74
+ utils.no_args(ctx)
75
+ return
76
+
77
+ # Normalize options
78
+ model_formats = mdlformat or None
79
+ if parent: relative = True
80
+ if animation: skeleton = True
81
+
82
+ # Relative flag is useless without output path
83
+ if relative and not output:
84
+ print(L.WARN, "Flag [b]--relative[/] requires [b]--output[/] option.")
85
+
86
+ # Warn if specified formats has unsupported features
87
+ if model_formats:
88
+ if skeleton: utils.check_feature_unsupported(model_formats, CLI.NON_SKELETAL_FORMATS, "skeleton")
89
+ if animation: utils.check_feature_unsupported(model_formats, CLI.NON_ANIMATION_FORMATS, "animation")
90
+
91
+ # Prepare options
92
+ options = UserOptions(
93
+ model_formats=model_formats,
94
+ parse_skeleton=skeleton,
95
+ parse_animation=animation,
96
+ overwrite=not unique,
97
+ )
98
+
99
+ # Iterate over each directory to their supported files
100
+ for root, source in utils.paths_to_files_map(paths):
101
+ # Get destination path
102
+ dest = utils.output_to_destination(root, source, output, relative, parent)
103
+
104
+ # Convert source file
105
+ try:
106
+ convert.auto(source=source, output=dest, options=options)
107
+
108
+ except exceptions.InvalidStructureError as err:
109
+ print(L.ERROR, str(err), CLI.EXCEPTION)
110
+
111
+ except exceptions.ScFileException as err:
112
+ print(L.ERROR, str(err))
113
+
114
+ except Exception as err:
115
+ traceback.print_exception(err)
116
+ print(L.EXCEPTION, f"File '{source.as_posix()}' {err}.", CLI.EXCEPTION)
117
+
118
+ else:
119
+ src_path = source.relative_to(root)
120
+ dst_path = dest or source.parent
121
+ print(L.INFO, f"File '{src_path.as_posix()}' converted to '{dst_path.as_posix()}'.")
scfile/cli/types.py ADDED
@@ -0,0 +1,21 @@
1
+ """
2
+ Data types for CLI wrapper.
3
+ """
4
+
5
+ import pathlib
6
+ from typing import Iterator, Optional, Sequence, Tuple, TypeAlias
7
+
8
+ import click
9
+
10
+ from scfile.consts import OutputFormats
11
+
12
+
13
+ PathType = pathlib.Path
14
+
15
+ FilesPaths: TypeAlias = Sequence[PathType]
16
+ FilesIter: TypeAlias = Iterator[Tuple[PathType, PathType]]
17
+ OutputDir: TypeAlias = Optional[PathType]
18
+
19
+ Files = click.Path(path_type=PathType, dir_okay=True, file_okay=True, exists=True, resolve_path=True)
20
+ Output = click.Path(path_type=PathType, dir_okay=True, file_okay=False)
21
+ Formats = click.Choice(list(OutputFormats.MODELS), case_sensitive=False)
scfile/cli/utils.py ADDED
@@ -0,0 +1,62 @@
1
+ """
2
+ CLI wrapper small utils.
3
+ """
4
+
5
+ from pathlib import Path
6
+
7
+ import click
8
+ from rich import print
9
+
10
+ from scfile.consts import CLI, SUPPORTED_SUFFIXES, Formats
11
+ from scfile.enums import L
12
+
13
+ from . import types
14
+
15
+
16
+ def no_args(ctx: click.Context) -> None:
17
+ """Prints help message when no arguments provided."""
18
+ click.echo(ctx.get_help())
19
+ print(
20
+ "",
21
+ f"{L.INVALID} No files paths arguments provided. Showing help.",
22
+ f"{L.HINT} Next time drag and drop files onto scfile.exe OR use terminal for parameters.",
23
+ sep="\n"
24
+ )
25
+ click.pause(CLI.PAUSE)
26
+
27
+
28
+ def check_feature_unsupported(user_formats: Formats, unsupported_formats: Formats, feature: str) -> None:
29
+ """Checks that user formats contain unsupported feature."""
30
+ matching_formats = list(filter(lambda fmt: fmt in unsupported_formats, user_formats))
31
+
32
+ if bool(matching_formats):
33
+ suffixes = ", ".join(map(lambda fmt: fmt.suffix, matching_formats))
34
+ print(L.WARN, f"Specified formats [b]({suffixes})[/] doesn't support {feature}.")
35
+
36
+
37
+ def is_supported(path: Path) -> bool:
38
+ """Checks that file is supported (by suffix)."""
39
+ return path.is_file() and path.suffix in SUPPORTED_SUFFIXES
40
+
41
+
42
+ def paths_to_files_map(paths: types.FilesPaths) -> types.FilesIter:
43
+ """Maps parent directories to their supported files."""
44
+ for path in paths:
45
+ path = path.resolve()
46
+
47
+ if path.is_file():
48
+ if is_supported(path):
49
+ yield path.parent, path
50
+
51
+ elif path.is_dir():
52
+ for file in path.rglob("*"):
53
+ if is_supported(file):
54
+ yield path, file
55
+
56
+
57
+ def output_to_destination(root: Path, source: Path, output: types.OutputDir, relative: bool, parent: bool) -> types.OutputDir:
58
+ """Output path with source relative subdirectory appended if relative flag."""
59
+ if relative and output:
60
+ basedir = root.parent if parent else root
61
+ return output / source.relative_to(basedir).parent
62
+ return output
scfile/consts.py ADDED
@@ -0,0 +1,106 @@
1
+ from typing import Sequence, TypeAlias
2
+
3
+ from .enums import FileFormat
4
+
5
+
6
+ Formats: TypeAlias = Sequence[FileFormat]
7
+
8
+
9
+ SUPPORTED_FORMATS: set[FileFormat] = {
10
+ FileFormat.MCSA,
11
+ FileFormat.MCSB,
12
+ FileFormat.MCVD,
13
+ FileFormat.MIC,
14
+ FileFormat.OL,
15
+ FileFormat.TEXARR,
16
+ }
17
+ """Files formats (suffixes without dot) that can be converted."""
18
+
19
+ SUPPORTED_SUFFIXES: set[str] = set(map(lambda fmt: fmt.suffix, SUPPORTED_FORMATS))
20
+ """Files suffixes that can be converted."""
21
+
22
+
23
+ class FileSignature:
24
+ """File magic number for formats (big-endian)."""
25
+
26
+ MCSA = b"MCSA"
27
+ MCAL = b"MCAL"
28
+ MIC = b"\x89MIC"
29
+ OL = b"\x0a\x95\x23\xfd"
30
+
31
+ DDS = b"DDS "
32
+ PNG = b"\x89PNG"
33
+ GLTF = b"glTF"
34
+ MS3D = b"MS3D000000"
35
+
36
+
37
+ class Factor:
38
+ """Integer max range for integer type."""
39
+
40
+ I8 = 0x7F
41
+ U8 = 0xFF
42
+ I16 = 0x7FFF
43
+ U16 = 0xFFFF
44
+
45
+
46
+ class OlString:
47
+ """Xor encoded zero-end string."""
48
+
49
+ SIZE = 17
50
+ """16 encoded bytes and last 0x00 byte."""
51
+ XOR = ord("g")
52
+ NULL = ord("G")
53
+
54
+
55
+ class CubemapFaces:
56
+ """Dds cubemap faces."""
57
+
58
+ FACES = {"+x", "-x", "+y", "-y", "+z", "-z"}
59
+ COUNT = len(FACES)
60
+
61
+
62
+ class McsaModel:
63
+ """Mcsa model constants."""
64
+
65
+ DECIMALS = 6
66
+ ROOT_BONE_ID = -1
67
+ GEOMETRY_LIMIT = 1_000_000
68
+ """Safety limit to prevent memory overflow on corrupted files."""
69
+
70
+
71
+ class McsaUnits:
72
+ """Mcsa structures elements count."""
73
+
74
+ POSITIONS = 4
75
+ TEXTURES = 2
76
+ NORMALS = 4
77
+ POLYGONS = 3
78
+ LINKS = 4
79
+ BONES = 6
80
+ FRAMES = 7
81
+
82
+
83
+ class CLI:
84
+ """Command line interface constants."""
85
+
86
+ FORMATS = EPILOG = f"Supported formats: {', '.join(sorted(SUPPORTED_SUFFIXES))}"
87
+ EXCEPTION = "[b yellow]Input file appears to be corrupted or invalid.[/]"
88
+ PAUSE = "\nPress any key to exit..."
89
+
90
+ NON_SKELETAL_FORMATS: Formats = (FileFormat.OBJ,)
91
+ NON_ANIMATION_FORMATS: Formats = (FileFormat.OBJ, FileFormat.MS3D, FileFormat.DAE)
92
+
93
+
94
+ class OutputFormats:
95
+ """Supported output formats for file data types."""
96
+
97
+ MODELS: Formats = (FileFormat.OBJ, FileFormat.GLB, FileFormat.DAE, FileFormat.MS3D)
98
+ TEXTURES: Formats = (FileFormat.DDS,)
99
+ IMAGES: Formats = (FileFormat.PNG,)
100
+
101
+
102
+ class DefaultModelFormats:
103
+ """Default model formats for cases where no preference is specified."""
104
+
105
+ STANDARD: Formats = (FileFormat.OBJ,)
106
+ SKELETON: Formats = (FileFormat.GLB,)
@@ -0,0 +1,33 @@
1
+ """
2
+ Utility module. Handles conversion logic between formats.
3
+ """
4
+
5
+ from . import base, legacy, detect, formats
6
+ from .detect import auto
7
+ from .formats import (
8
+ mcsb_to_dae,
9
+ mcsb_to_glb,
10
+ mcsb_to_ms3d,
11
+ mcsb_to_obj,
12
+ ol_to_dds,
13
+ ol_cubemap_to_dds,
14
+ mic_to_png,
15
+ texarr_to_zip,
16
+ )
17
+
18
+
19
+ __all__ = (
20
+ "base",
21
+ "legacy",
22
+ "detect",
23
+ "formats",
24
+ "auto",
25
+ "mcsb_to_dae",
26
+ "mcsb_to_glb",
27
+ "mcsb_to_ms3d",
28
+ "mcsb_to_obj",
29
+ "ol_to_dds",
30
+ "ol_cubemap_to_dds",
31
+ "mic_to_png",
32
+ "texarr_to_zip",
33
+ )