mntm-asset-packer 1.1.1__py3-none-any.whl → 1.1.2__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.
- {mntm_asset_packer-1.1.1.dist-info → mntm_asset_packer-1.1.2.dist-info}/METADATA +2 -2
- mntm_asset_packer-1.1.2.dist-info/RECORD +5 -0
- mntm_asset_packer.py +245 -193
- mntm_asset_packer-1.1.1.dist-info/RECORD +0 -5
- {mntm_asset_packer-1.1.1.dist-info → mntm_asset_packer-1.1.2.dist-info}/WHEEL +0 -0
- {mntm_asset_packer-1.1.1.dist-info → mntm_asset_packer-1.1.2.dist-info}/entry_points.txt +0 -0
@@ -1,8 +1,8 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: mntm-asset-packer
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.2
|
4
4
|
Summary: An improved asset packer script to make the process of creating and packing asset packs for the Momentum firmware easier.
|
5
|
-
Author-email: notnotnescap <
|
5
|
+
Author-email: notnotnescap <nescap@tuta.io>
|
6
6
|
Requires-Python: >=3.11
|
7
7
|
Requires-Dist: heatshrink2>=0.13.0
|
8
8
|
Requires-Dist: pillow>=11.2.1
|
@@ -0,0 +1,5 @@
|
|
1
|
+
mntm_asset_packer.py,sha256=xR-9IpKDWbgfTVBrvDBve_jEhIfy8zT0Od-gau48XzQ,26765
|
2
|
+
mntm_asset_packer-1.1.2.dist-info/METADATA,sha256=Q6x7aVPiOPYROpKYnmJoR6wBKsuVQlw3YQGI1mel1Es,3621
|
3
|
+
mntm_asset_packer-1.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
4
|
+
mntm_asset_packer-1.1.2.dist-info/entry_points.txt,sha256=CF05qVMVPPNhTroKeH_kkKqVgG-mJ-Q0mSAZHpfxkr0,61
|
5
|
+
mntm_asset_packer-1.1.2.dist-info/RECORD,,
|
mntm_asset_packer.py
CHANGED
@@ -1,31 +1,36 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
|
-
"""
|
3
|
-
|
2
|
+
"""Script to pack and recover asset packs for Momentum.
|
3
|
+
|
4
|
+
I recommend installing the mntm-asset-packer package from PyPI instead of using this script directly.
|
5
|
+
more info here: https://github.com/notnotnescap/mntm-asset-packer
|
4
6
|
This is a modification of the original asset_packer script by @Willy-JL
|
5
7
|
"""
|
6
8
|
|
9
|
+
import importlib.metadata
|
10
|
+
import io
|
11
|
+
import os
|
7
12
|
import pathlib
|
13
|
+
import re
|
8
14
|
import shutil
|
9
15
|
import struct
|
10
|
-
import typing
|
11
|
-
import time
|
12
|
-
import re
|
13
|
-
import io
|
14
|
-
import os
|
15
16
|
import sys
|
16
|
-
|
17
|
+
import time
|
18
|
+
import typing
|
19
|
+
from pathlib import Path
|
20
|
+
|
17
21
|
import heatshrink2
|
22
|
+
from PIL import Image, ImageOps
|
18
23
|
|
19
|
-
HELP_MESSAGE = """The asset packer converts animations with a specific structure to be
|
20
|
-
with the asset pack system used in Momentum.
|
24
|
+
HELP_MESSAGE = """The asset packer converts animations with a specific structure to be \
|
25
|
+
efficient and compatible with the asset pack system used in Momentum.
|
26
|
+
More info: https://github.com/Kuronons/FZ_graphics
|
21
27
|
|
22
28
|
Usage :
|
23
29
|
\033[32mmntm-asset-packer \033[0;33;1mhelp\033[0m
|
24
30
|
\033[3mDisplays this message
|
25
31
|
\033[0m
|
26
32
|
\033[32mmntm-asset-packer \033[0;33;1mcreate <Asset Pack Name>\033[0m
|
27
|
-
\033[3mCreates a directory with the correct file structure that can be used
|
28
|
-
to prepare for the packing process.
|
33
|
+
\033[3mCreates a directory with the correct file structure that can be used to prepare for the packing process.
|
29
34
|
\033[0m
|
30
35
|
\033[32mmntm-asset-packer \033[0;33;1mpack <./path/to/AssetPack>\033[0m
|
31
36
|
\033[3mPacks the specified asset pack into './asset_packs/AssetPack'
|
@@ -37,15 +42,13 @@ Usage :
|
|
37
42
|
\033[3mSame as 'mntm-asset-packer pack all'
|
38
43
|
\033[0m
|
39
44
|
\033[32mmntm-asset-packer \033[0;33;1mrecover <./asset_packs/AssetPack>\033[0m
|
40
|
-
\033[3mRecovers the png frame(s) from a compiled assets for the specified asset pack
|
41
|
-
The recovered asset pack is saved in './recovered/AssetPack'
|
45
|
+
\033[3mRecovers the png frame(s) from a compiled assets for the specified asset pack. The recovered asset pack is saved in './recovered/AssetPack'
|
42
46
|
\033[0m
|
43
47
|
\033[32mmntm-asset-packer \033[0;33;1mrecover all\033[0m
|
44
48
|
\033[3mRecovers all asset packs in './asset_packs/' into './recovered/'
|
45
49
|
\033[0m
|
46
50
|
\033[32mmntm-asset-packer \033[0;33;1mconvert <./path/to/AssetPack>\033[0m
|
47
|
-
\033[3mConverts all anim frames to .png files and renames them to the correct format.
|
48
|
-
(requires numbers in filenames)
|
51
|
+
\033[3mConverts all anim frames to .png files and renames them to the correct format. (requires numbers in filenames)
|
49
52
|
\033[0m
|
50
53
|
"""
|
51
54
|
|
@@ -78,9 +81,11 @@ Active cooldown: 0
|
|
78
81
|
Bubble slots: 0
|
79
82
|
"""
|
80
83
|
|
84
|
+
VERSION = importlib.metadata.version("mntm-asset-packer")
|
85
|
+
|
81
86
|
|
82
87
|
def convert_to_bm(img: "Image.Image | pathlib.Path") -> bytes:
|
83
|
-
"""Converts an image to a bitmap"""
|
88
|
+
"""Converts an image to a bitmap."""
|
84
89
|
if not isinstance(img, Image.Image):
|
85
90
|
img = Image.open(img)
|
86
91
|
|
@@ -107,7 +112,7 @@ def convert_to_bm(img: "Image.Image | pathlib.Path") -> bytes:
|
|
107
112
|
|
108
113
|
|
109
114
|
def convert_to_bmx(img: "Image.Image | pathlib.Path") -> bytes:
|
110
|
-
"""Converts an image to a bmx that contains image size info"""
|
115
|
+
"""Converts an image to a bmx that contains image size info."""
|
111
116
|
if not isinstance(img, Image.Image):
|
112
117
|
img = Image.open(img)
|
113
118
|
|
@@ -117,15 +122,15 @@ def convert_to_bmx(img: "Image.Image | pathlib.Path") -> bytes:
|
|
117
122
|
|
118
123
|
|
119
124
|
def recover_from_bm(bm: "bytes | pathlib.Path", width: int, height: int) -> Image.Image:
|
120
|
-
"""Converts a bitmap back to a png (same as convert_to_bm but in reverse)
|
121
|
-
|
122
|
-
|
125
|
+
"""Converts a bitmap back to a png (same as convert_to_bm but in reverse).
|
126
|
+
|
127
|
+
The resulting png will not always be the same as the original image as some
|
128
|
+
information is lost during the conversion.
|
129
|
+
"""
|
123
130
|
if not isinstance(bm, bytes):
|
124
131
|
bm = bm.read_bytes()
|
125
132
|
|
126
|
-
|
127
|
-
|
128
|
-
if bm.startswith(b'\x01\x00'):
|
133
|
+
if bm.startswith(b"\x01\x00"):
|
129
134
|
data_dec = heatshrink2.decompress(bm[4:], window_sz2=8, lookahead_sz2=4)
|
130
135
|
else:
|
131
136
|
data_dec = bm[1:]
|
@@ -139,7 +144,7 @@ def recover_from_bm(bm: "bytes | pathlib.Path", width: int, height: int) -> Imag
|
|
139
144
|
if len(pixels) < num_target_pixels:
|
140
145
|
pixels.append(1 - ((byte_val >> i) & 1))
|
141
146
|
else:
|
142
|
-
break
|
147
|
+
break
|
143
148
|
if len(pixels) >= num_target_pixels:
|
144
149
|
break
|
145
150
|
|
@@ -149,7 +154,7 @@ def recover_from_bm(bm: "bytes | pathlib.Path", width: int, height: int) -> Imag
|
|
149
154
|
|
150
155
|
|
151
156
|
def recover_from_bmx(bmx: "bytes | pathlib.Path") -> Image.Image:
|
152
|
-
"""Converts a bmx back to a png (same as convert_to_bmx but in reverse)"""
|
157
|
+
"""Converts a bmx back to a png (same as convert_to_bmx but in reverse)."""
|
153
158
|
if not isinstance(bmx, bytes):
|
154
159
|
bmx = bmx.read_bytes()
|
155
160
|
|
@@ -157,21 +162,23 @@ def recover_from_bmx(bmx: "bytes | pathlib.Path") -> Image.Image:
|
|
157
162
|
return recover_from_bm(bmx[8:], width, height)
|
158
163
|
|
159
164
|
|
160
|
-
def copy_file_as_lf(src: "pathlib.Path", dst: "pathlib.Path"):
|
161
|
-
"""Copy file but replace Windows Line Endings with Unix Line Endings"""
|
165
|
+
def copy_file_as_lf(src: "pathlib.Path", dst: "pathlib.Path") -> None:
|
166
|
+
"""Copy file but replace Windows Line Endings with Unix Line Endings."""
|
162
167
|
dst.write_bytes(src.read_bytes().replace(b"\r\n", b"\n"))
|
163
168
|
|
164
169
|
|
165
|
-
def pack_anim(src: pathlib.Path, dst: pathlib.Path):
|
166
|
-
"""Packs an anim"""
|
170
|
+
def pack_anim(src: pathlib.Path, dst: pathlib.Path) -> None:
|
171
|
+
"""Packs an anim."""
|
167
172
|
if not (src / "meta.txt").is_file():
|
168
|
-
print(f
|
173
|
+
print(f'\033[31mNo meta.txt found in "{src.name}" anim.\033[0m')
|
169
174
|
return
|
170
175
|
if not any(re.match(r"frame_\d+.(png|bm)", file.name) for file in src.iterdir()):
|
171
|
-
print(
|
176
|
+
print(
|
177
|
+
f'\033[31mNo frames with the required format found in "{src.name}" anim.\033[0m',
|
178
|
+
)
|
172
179
|
try:
|
173
180
|
input(
|
174
|
-
"Press [Enter] to convert and rename the frames or [Ctrl+C] to cancel\033[0m"
|
181
|
+
"Press [Enter] to convert and rename the frames or [Ctrl+C] to cancel\033[0m",
|
175
182
|
)
|
176
183
|
except KeyboardInterrupt:
|
177
184
|
sys.exit(0)
|
@@ -187,18 +194,19 @@ def pack_anim(src: pathlib.Path, dst: pathlib.Path):
|
|
187
194
|
elif frame.name.startswith("frame_"):
|
188
195
|
if frame.suffix == ".png":
|
189
196
|
(dst / frame.with_suffix(".bm").name).write_bytes(convert_to_bm(frame))
|
190
|
-
elif frame.suffix == ".bm":
|
191
|
-
|
192
|
-
shutil.copyfile(frame, dst / frame.name)
|
197
|
+
elif frame.suffix == ".bm" and not (dst / frame.name).is_file():
|
198
|
+
shutil.copyfile(frame, dst / frame.name)
|
193
199
|
|
194
200
|
|
195
|
-
def recover_anim(src: pathlib.Path, dst: pathlib.Path):
|
196
|
-
"""Converts a bitmap to a png"""
|
197
|
-
if not
|
198
|
-
print(f
|
201
|
+
def recover_anim(src: pathlib.Path, dst: pathlib.Path) -> None:
|
202
|
+
"""Converts a bitmap to a png."""
|
203
|
+
if not Path.exists(src):
|
204
|
+
print(f'\033[31mError: "{src}" not found\033[0m')
|
199
205
|
return
|
200
206
|
if not any(re.match(r"frame_\d+.bm", file.name) for file in src.iterdir()):
|
201
|
-
print(
|
207
|
+
print(
|
208
|
+
f'\033[31mNo frames with the required format found in "{src.name}" anim.\033[0m',
|
209
|
+
)
|
202
210
|
return
|
203
211
|
|
204
212
|
dst.mkdir(parents=True, exist_ok=True)
|
@@ -206,9 +214,9 @@ def recover_anim(src: pathlib.Path, dst: pathlib.Path):
|
|
206
214
|
width = 128
|
207
215
|
height = 64
|
208
216
|
meta = src / "meta.txt"
|
209
|
-
if
|
217
|
+
if Path.exists(meta):
|
210
218
|
shutil.copyfile(meta, dst / meta.name)
|
211
|
-
with open(meta,
|
219
|
+
with Path.open(meta, encoding="utf-8") as f:
|
212
220
|
for line in f:
|
213
221
|
if line.startswith("Width:"):
|
214
222
|
width = int(line.split(":")[1].strip())
|
@@ -223,8 +231,8 @@ def recover_anim(src: pathlib.Path, dst: pathlib.Path):
|
|
223
231
|
img.save(dst / file.with_suffix(".png").name)
|
224
232
|
|
225
233
|
|
226
|
-
def pack_animated_icon(src: pathlib.Path, dst: pathlib.Path):
|
227
|
-
"""Packs an animated
|
234
|
+
def pack_animated_icon(src: pathlib.Path, dst: pathlib.Path) -> None:
|
235
|
+
"""Packs an animated ico."""
|
228
236
|
if not (src / "frame_rate").is_file() and not (src / "meta").is_file():
|
229
237
|
return
|
230
238
|
dst.mkdir(parents=True, exist_ok=True)
|
@@ -254,8 +262,8 @@ def pack_animated_icon(src: pathlib.Path, dst: pathlib.Path):
|
|
254
262
|
(dst / "meta").write_bytes(struct.pack("<IIII", *size, frame_rate, frame_count))
|
255
263
|
|
256
264
|
|
257
|
-
def recover_animated_icon(src: pathlib.Path, dst: pathlib.Path):
|
258
|
-
"""Recovers an animated icon"""
|
265
|
+
def recover_animated_icon(src: pathlib.Path, dst: pathlib.Path) -> None:
|
266
|
+
"""Recovers an animated icon."""
|
259
267
|
meta_file_path = src / "meta"
|
260
268
|
|
261
269
|
if not meta_file_path.is_file():
|
@@ -263,7 +271,7 @@ def recover_animated_icon(src: pathlib.Path, dst: pathlib.Path):
|
|
263
271
|
|
264
272
|
unpacked_meta_data = None
|
265
273
|
try:
|
266
|
-
with open(meta_file_path, "rb") as f:
|
274
|
+
with Path.open(meta_file_path, "rb") as f:
|
267
275
|
expected_bytes_count = struct.calcsize("<IIII")
|
268
276
|
data_bytes = f.read(expected_bytes_count)
|
269
277
|
if len(data_bytes) < expected_bytes_count:
|
@@ -271,9 +279,11 @@ def recover_animated_icon(src: pathlib.Path, dst: pathlib.Path):
|
|
271
279
|
return
|
272
280
|
unpacked_meta_data = struct.unpack("<IIII", data_bytes)
|
273
281
|
except struct.error:
|
274
|
-
print(
|
282
|
+
print(
|
283
|
+
f"Error: Failed to unpack meta file '{meta_file_path}'. It might be corrupted.",
|
284
|
+
)
|
275
285
|
return
|
276
|
-
except
|
286
|
+
except OSError as e: # Catch file-related IO errors
|
277
287
|
print(f"Error reading meta file '{meta_file_path}': {e}")
|
278
288
|
return
|
279
289
|
|
@@ -293,45 +303,38 @@ def recover_animated_icon(src: pathlib.Path, dst: pathlib.Path):
|
|
293
303
|
try:
|
294
304
|
frame = recover_from_bm(frame_bm_file_path, image_width, image_height)
|
295
305
|
frame.save(dst / f"frame_{i:02}.png")
|
296
|
-
except
|
306
|
+
except (OSError, ValueError) as e:
|
297
307
|
print(f"Error recovering or saving frame '{frame_bm_file_path}': {e}")
|
298
|
-
continue
|
308
|
+
continue # skip to the next frame if an error occurs
|
299
309
|
|
300
310
|
(dst / "frame_rate").write_text(str(frame_rate_value))
|
301
311
|
|
302
312
|
|
303
|
-
def pack_static_icon(src: pathlib.Path, dst: pathlib.Path):
|
304
|
-
"""Packs a static icon"""
|
313
|
+
def pack_static_icon(src: pathlib.Path, dst: pathlib.Path) -> None:
|
314
|
+
"""Packs a static icon."""
|
305
315
|
dst.parent.mkdir(parents=True, exist_ok=True)
|
306
316
|
if src.suffix == ".png":
|
307
317
|
dst.with_suffix(".bmx").write_bytes(convert_to_bmx(src))
|
308
|
-
elif src.suffix == ".bmx":
|
309
|
-
|
310
|
-
shutil.copyfile(src, dst)
|
318
|
+
elif src.suffix == ".bmx" and not dst.is_file():
|
319
|
+
shutil.copyfile(src, dst)
|
311
320
|
|
312
321
|
|
313
|
-
def recover_static_icon(src: pathlib.Path, dst: pathlib.Path):
|
314
|
-
"""Recovers a static icon"""
|
322
|
+
def recover_static_icon(src: pathlib.Path, dst: pathlib.Path) -> None:
|
323
|
+
"""Recovers a static icon."""
|
315
324
|
dst.parent.mkdir(parents=True, exist_ok=True)
|
316
325
|
if src.suffix == ".bmx":
|
317
326
|
recover_from_bmx(src).save(dst.with_suffix(".png"))
|
318
327
|
|
319
328
|
|
320
|
-
def pack_font(src: pathlib.Path, dst: pathlib.Path):
|
321
|
-
"""Packs a font"""
|
329
|
+
def pack_font(src: pathlib.Path, dst: pathlib.Path) -> None:
|
330
|
+
"""Packs a font."""
|
322
331
|
dst.parent.mkdir(parents=True, exist_ok=True)
|
323
332
|
if src.suffix == ".c":
|
324
|
-
code = (
|
325
|
-
src.read_bytes().split(b' U8G2_FONT_SECTION("')[1].split(b'") =')[1].strip()
|
326
|
-
)
|
333
|
+
code = src.read_bytes().split(b' U8G2_FONT_SECTION("')[1].split(b'") =')[1].strip()
|
327
334
|
font = b""
|
328
335
|
for line in code.splitlines():
|
329
336
|
if line.count(b'"') == 2:
|
330
|
-
font += (
|
331
|
-
line[line.find(b'"') + 1 : line.rfind(b'"')]
|
332
|
-
.decode("unicode_escape")
|
333
|
-
.encode("latin_1")
|
334
|
-
)
|
337
|
+
font += line[line.find(b'"') + 1 : line.rfind(b'"')].decode("unicode_escape").encode("latin_1")
|
335
338
|
font += b"\0"
|
336
339
|
dst.with_suffix(".u8f").write_bytes(font)
|
337
340
|
elif src.suffix == ".u8f":
|
@@ -342,27 +345,25 @@ def pack_font(src: pathlib.Path, dst: pathlib.Path):
|
|
342
345
|
# recover font is not implemented
|
343
346
|
|
344
347
|
|
345
|
-
def convert_and_rename_frames(directory: "str | pathlib.Path", logger: typing.Callable):
|
346
|
-
"""Converts all frames to png and renames them "frame_N.png"
|
347
|
-
|
348
|
+
def convert_and_rename_frames(directory: "str | pathlib.Path", logger: typing.Callable) -> None:
|
349
|
+
"""Converts all frames to png and renames them "frame_N.png".
|
350
|
+
|
351
|
+
(requires the image name to contain the frame number)
|
352
|
+
"""
|
348
353
|
already_formatted = True
|
349
354
|
for file in directory.iterdir():
|
350
|
-
if file.is_file() and file.suffix in (".jpg", ".jpeg", ".png"):
|
351
|
-
|
352
|
-
|
353
|
-
break
|
355
|
+
if file.is_file() and file.suffix in (".jpg", ".jpeg", ".png") and not re.match(r"frame_\d+.png", file.name):
|
356
|
+
already_formatted = False
|
357
|
+
break
|
354
358
|
if already_formatted:
|
355
|
-
logger(f"
|
359
|
+
logger(f'"{directory.name}" anim is formatted')
|
356
360
|
return
|
357
361
|
|
358
362
|
try:
|
359
363
|
print(
|
360
|
-
f
|
361
|
-
"This action is irreversible, make sure to back up your files if needed.\n\033[0m"
|
362
|
-
)
|
363
|
-
input(
|
364
|
-
"Press [Enter] if you wish to continue or [Ctrl+C] to cancel"
|
364
|
+
f'\033[31mThis will convert all frames for the "{directory.name}" anim to png and rename them.\nThis action is irreversible, make sure to back up your files if needed.\n\033[0m',
|
365
365
|
)
|
366
|
+
input("Press [Enter] if you wish to continue or [Ctrl+C] to cancel")
|
366
367
|
except KeyboardInterrupt:
|
367
368
|
sys.exit(0)
|
368
369
|
print()
|
@@ -382,16 +383,26 @@ def convert_and_rename_frames(directory: "str | pathlib.Path", logger: typing.Ca
|
|
382
383
|
file.unlink()
|
383
384
|
|
384
385
|
|
385
|
-
def convert_and_rename_frames_for_all_anims(
|
386
|
-
|
387
|
-
|
386
|
+
def convert_and_rename_frames_for_all_anims(
|
387
|
+
directory_for_anims: "str | pathlib.Path",
|
388
|
+
logger: typing.Callable,
|
389
|
+
) -> None:
|
390
|
+
"""Formats all anim frames correctly.
|
391
|
+
|
392
|
+
Converts all frames to png and renames them "frame_N.png for all anims in the given anim folder.
|
393
|
+
(requires the image name to contain the frame number)
|
394
|
+
"""
|
388
395
|
for anim in directory_for_anims.iterdir():
|
389
396
|
if anim.is_dir():
|
390
397
|
convert_and_rename_frames(anim, logger)
|
391
398
|
|
392
399
|
|
393
|
-
def pack_specific(
|
394
|
-
"
|
400
|
+
def pack_specific(
|
401
|
+
asset_pack_path: "str | pathlib.Path",
|
402
|
+
output_directory: "str | pathlib.Path",
|
403
|
+
logger: typing.Callable,
|
404
|
+
) -> None:
|
405
|
+
"""Packs a specific asset pack."""
|
395
406
|
asset_pack_path = pathlib.Path(asset_pack_path)
|
396
407
|
output_directory = pathlib.Path(output_directory)
|
397
408
|
logger(f"Packing '\033[3m{asset_pack_path.name}\033[0m'")
|
@@ -413,22 +424,23 @@ def pack_specific(asset_pack_path: "str | pathlib.Path", output_directory: "str
|
|
413
424
|
|
414
425
|
# packing anims
|
415
426
|
if (asset_pack_path / "Anims/manifest.txt").exists():
|
416
|
-
(packed / "Anims").mkdir(
|
417
|
-
|
427
|
+
(packed / "Anims").mkdir(
|
428
|
+
parents=True,
|
429
|
+
exist_ok=True,
|
430
|
+
) # ensure that the "Anims" directory exists
|
431
|
+
copy_file_as_lf(
|
432
|
+
asset_pack_path / "Anims/manifest.txt",
|
433
|
+
packed / "Anims/manifest.txt",
|
434
|
+
)
|
418
435
|
manifest = (asset_pack_path / "Anims/manifest.txt").read_bytes()
|
419
436
|
|
420
437
|
# Find all the anims in the manifest
|
421
438
|
for anim in re.finditer(rb"Name: (.*)", manifest):
|
422
|
-
|
423
|
-
|
424
|
-
.
|
425
|
-
.replace("\\", "/")
|
426
|
-
.replace("/", os.sep)
|
427
|
-
.replace("\r", "\n")
|
428
|
-
.strip()
|
439
|
+
anim_name = anim.group(1).decode().replace("\\", "/").replace("/", os.sep).replace("\r", "\n").strip()
|
440
|
+
logger(
|
441
|
+
f"Compiling anim '\033[3m{anim_name}\033[0m' for '\033[3m{asset_pack_path.name}\033[0m'",
|
429
442
|
)
|
430
|
-
|
431
|
-
pack_anim(asset_pack_path / "Anims" / anim, packed / "Anims" / anim)
|
443
|
+
pack_anim(asset_pack_path / "Anims" / anim_name, packed / "Anims" / anim_name)
|
432
444
|
|
433
445
|
# packing icons
|
434
446
|
if (asset_pack_path / "Icons").is_dir():
|
@@ -439,20 +451,20 @@ def pack_specific(asset_pack_path: "str | pathlib.Path", output_directory: "str
|
|
439
451
|
if icon.name.startswith("."):
|
440
452
|
continue
|
441
453
|
if icon.is_dir():
|
442
|
-
logger(
|
454
|
+
logger(
|
455
|
+
f"Compiling icon for pack '{asset_pack_path.name}': {icons.name}/{icon.name}",
|
456
|
+
)
|
443
457
|
pack_animated_icon(icon, packed / "Icons" / icons.name / icon.name)
|
444
458
|
elif icon.is_file() and icon.suffix in (".png", ".bmx"):
|
445
|
-
logger(
|
459
|
+
logger(
|
460
|
+
f"Compiling icon for pack '{asset_pack_path.name}': {icons.name}/{icon.name}",
|
461
|
+
)
|
446
462
|
pack_static_icon(icon, packed / "Icons" / icons.name / icon.name)
|
447
463
|
|
448
464
|
# packing fonts
|
449
465
|
if (asset_pack_path / "Fonts").is_dir():
|
450
466
|
for font in (asset_pack_path / "Fonts").iterdir():
|
451
|
-
if (
|
452
|
-
not font.is_file()
|
453
|
-
or font.name.startswith(".")
|
454
|
-
or font.suffix not in (".c", ".u8f")
|
455
|
-
):
|
467
|
+
if not font.is_file() or font.name.startswith(".") or font.suffix not in (".c", ".u8f"):
|
456
468
|
continue
|
457
469
|
logger(f"Compiling font for pack '{asset_pack_path.name}': {font.name}")
|
458
470
|
pack_font(font, packed / "Fonts" / font.name)
|
@@ -461,8 +473,12 @@ def pack_specific(asset_pack_path: "str | pathlib.Path", output_directory: "str
|
|
461
473
|
logger(f"Saved to: '\033[33m{packed}\033[0m'")
|
462
474
|
|
463
475
|
|
464
|
-
def recover_specific(
|
465
|
-
"
|
476
|
+
def recover_specific(
|
477
|
+
asset_pack_path: "str | pathlib.Path",
|
478
|
+
output_directory: "str | pathlib.Path",
|
479
|
+
logger: typing.Callable,
|
480
|
+
) -> None:
|
481
|
+
"""Recovers a specific asset pack."""
|
466
482
|
asset_pack_path = pathlib.Path(asset_pack_path)
|
467
483
|
output_directory = pathlib.Path(output_directory)
|
468
484
|
logger(f"Recovering '\033[3m{asset_pack_path.name}\033[0m'")
|
@@ -484,11 +500,17 @@ def recover_specific(asset_pack_path: "str | pathlib.Path", output_directory: "s
|
|
484
500
|
|
485
501
|
# recovering anims
|
486
502
|
if (asset_pack_path / "Anims").is_dir():
|
487
|
-
(recovered / "Anims").mkdir(
|
503
|
+
(recovered / "Anims").mkdir(
|
504
|
+
parents=True,
|
505
|
+
exist_ok=True,
|
506
|
+
) # ensure that the "Anims" directory exists
|
488
507
|
|
489
508
|
# copy the manifest if it exists
|
490
509
|
if (asset_pack_path / "Anims/manifest.txt").exists():
|
491
|
-
shutil.copyfile(
|
510
|
+
shutil.copyfile(
|
511
|
+
asset_pack_path / "Anims/manifest.txt",
|
512
|
+
recovered / "Anims/manifest.txt",
|
513
|
+
)
|
492
514
|
|
493
515
|
# recover all the anims in the Anims directory
|
494
516
|
for anim in (asset_pack_path / "Anims").iterdir():
|
@@ -514,31 +536,24 @@ def recover_specific(asset_pack_path: "str | pathlib.Path", output_directory: "s
|
|
514
536
|
|
515
537
|
# recovering fonts
|
516
538
|
if (asset_pack_path / "Fonts").is_dir():
|
517
|
-
|
518
|
-
# if (
|
519
|
-
# not font.is_file()
|
520
|
-
# or font.name.startswith(".")
|
521
|
-
# or font.suffix not in (".c", ".u8f")
|
522
|
-
# ):
|
523
|
-
# continue
|
524
|
-
# logger(f"Compiling font for pack '{asset_pack_path.name}': {font.name}")
|
525
|
-
# pack_font(font, recovered / "Fonts" / font.name)
|
526
|
-
logger("Fonts recovery not implemented yet") #TODO: implement
|
539
|
+
logger("Fonts recovery not implemented yet")
|
527
540
|
|
528
541
|
logger(f"\033[32mFinished recovering '\033[3m{asset_pack_path.name}\033[23m'\033[0m")
|
529
542
|
logger(f"Saved to: '\033[33m{recovered}\033[0m'")
|
530
543
|
|
531
544
|
|
532
|
-
def pack_all_asset_packs(
|
533
|
-
"
|
545
|
+
def pack_all_asset_packs(
|
546
|
+
source_directory: "str | pathlib.Path",
|
547
|
+
output_directory: "str | pathlib.Path",
|
548
|
+
logger: typing.Callable,
|
549
|
+
) -> None:
|
550
|
+
"""Packs all asset packs in the source directory."""
|
534
551
|
try:
|
535
552
|
print(
|
536
|
-
"This will pack all asset packs in the current directory
|
537
|
-
"The resulting asset packs will be saved to './asset_packs'\n"
|
538
|
-
)
|
539
|
-
input(
|
540
|
-
"Press [Enter] if you wish to continue or [Ctrl+C] to cancel"
|
553
|
+
"This will pack all asset packs in the current directory."
|
554
|
+
"The resulting asset packs will be saved to './asset_packs'\n",
|
541
555
|
)
|
556
|
+
input("Press [Enter] if you wish to continue or [Ctrl+C] to cancel")
|
542
557
|
except KeyboardInterrupt:
|
543
558
|
sys.exit(0)
|
544
559
|
print()
|
@@ -550,22 +565,24 @@ def pack_all_asset_packs(source_directory: "str | pathlib.Path", output_director
|
|
550
565
|
# Skip folders that are definitely not meant to be packed
|
551
566
|
if source == output_directory:
|
552
567
|
continue
|
553
|
-
if not source.is_dir() or source.name.startswith(".") or source.name in ("venv", "recovered")
|
568
|
+
if not source.is_dir() or source.name.startswith(".") or source.name in ("venv", "recovered"):
|
554
569
|
continue
|
555
570
|
|
556
571
|
pack_specific(source, output_directory, logger)
|
557
572
|
|
558
573
|
|
559
|
-
def recover_all_asset_packs(
|
560
|
-
"
|
574
|
+
def recover_all_asset_packs(
|
575
|
+
source_directory: "str | pathlib.Path",
|
576
|
+
output_directory: "str | pathlib.Path",
|
577
|
+
logger: typing.Callable,
|
578
|
+
) -> None:
|
579
|
+
"""Recovers all asset packs in the source directory."""
|
561
580
|
try:
|
562
581
|
print(
|
563
|
-
"This will recover all asset packs in the current directory
|
564
|
-
"The resulting asset packs will be saved to './recovered'\n"
|
565
|
-
)
|
566
|
-
input(
|
567
|
-
"Press [Enter] if you wish to continue or [Ctrl+C] to cancel"
|
582
|
+
"This will recover all asset packs in the current directory."
|
583
|
+
"The resulting asset packs will be saved to './recovered'\n",
|
568
584
|
)
|
585
|
+
input("Press [Enter] if you wish to continue or [Ctrl+C] to cancel")
|
569
586
|
except KeyboardInterrupt:
|
570
587
|
sys.exit(0)
|
571
588
|
print()
|
@@ -577,15 +594,18 @@ def recover_all_asset_packs(source_directory: "str | pathlib.Path", output_direc
|
|
577
594
|
# Skip folders that are definitely not meant to be recovered
|
578
595
|
if source == output_directory:
|
579
596
|
continue
|
580
|
-
if not source.is_dir() or source.name.startswith(".") or source.name in ("venv", "recovered")
|
597
|
+
if not source.is_dir() or source.name.startswith(".") or source.name in ("venv", "recovered"):
|
581
598
|
continue
|
582
599
|
|
583
600
|
recover_specific(source, output_directory, logger)
|
584
601
|
|
585
602
|
|
586
|
-
def create_asset_pack(
|
587
|
-
|
588
|
-
|
603
|
+
def create_asset_pack(
|
604
|
+
asset_pack_name: str,
|
605
|
+
output_directory: "str | pathlib.Path",
|
606
|
+
logger: typing.Callable,
|
607
|
+
) -> None:
|
608
|
+
"""Creates the file structure for an asset pack."""
|
589
609
|
if not isinstance(output_directory, pathlib.Path):
|
590
610
|
output_directory = pathlib.Path(output_directory)
|
591
611
|
|
@@ -607,74 +627,106 @@ def create_asset_pack(asset_pack_name: str, output_directory: "str | pathlib.Pat
|
|
607
627
|
# creating "manifest.txt" file
|
608
628
|
if generate_example_files:
|
609
629
|
(output_directory / asset_pack_name / "Anims" / "manifest.txt").touch()
|
610
|
-
with open(
|
630
|
+
with Path.open(
|
631
|
+
output_directory / asset_pack_name / "Anims" / "manifest.txt",
|
632
|
+
"w",
|
633
|
+
encoding="utf-8",
|
634
|
+
) as f:
|
611
635
|
f.write(EXAMPLE_MANIFEST)
|
612
|
-
(output_directory / asset_pack_name / "Anims" / "example_anim").mkdir(
|
636
|
+
(output_directory / asset_pack_name / "Anims" / "example_anim").mkdir(
|
637
|
+
parents=True,
|
638
|
+
)
|
613
639
|
(output_directory / asset_pack_name / "Anims" / "example_anim" / "meta.txt").touch()
|
614
|
-
with open(
|
640
|
+
with Path.open(
|
641
|
+
output_directory / asset_pack_name / "Anims" / "example_anim" / "meta.txt",
|
642
|
+
"w",
|
643
|
+
encoding="utf-8",
|
644
|
+
) as f:
|
615
645
|
f.write(EXAMPLE_META)
|
616
646
|
|
617
647
|
logger(f"Created asset pack '{asset_pack_name}' in '{output_directory}'")
|
618
648
|
|
619
649
|
|
620
|
-
def main():
|
621
|
-
"""Main function"""
|
622
|
-
if len(sys.argv)
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
create_asset_pack(NAME, pathlib.Path.cwd(), logger=print)
|
631
|
-
|
632
|
-
else:
|
633
|
-
print(HELP_MESSAGE)
|
650
|
+
def main() -> None:
|
651
|
+
"""Main function."""
|
652
|
+
if len(sys.argv) <= 1:
|
653
|
+
# If no arguments are provided, pack all
|
654
|
+
here = pathlib.Path(__file__).absolute().parent
|
655
|
+
start = time.perf_counter()
|
656
|
+
pack_all_asset_packs(here, here / "asset_packs", logger=print)
|
657
|
+
end = time.perf_counter()
|
658
|
+
print(f"\nFinished in {round(end - start, 2)}s\n")
|
659
|
+
return
|
634
660
|
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
start = time.perf_counter()
|
661
|
+
match sys.argv[1]:
|
662
|
+
case "--version" | "-v":
|
663
|
+
print(f"mntm-asset-packer {VERSION}")
|
639
664
|
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
pack_specific(sys.argv[2], pathlib.Path.cwd() / "asset_packs", logger=print)
|
665
|
+
case "help" | "-h" | "--help":
|
666
|
+
print(HELP_MESSAGE)
|
667
|
+
return
|
644
668
|
|
645
|
-
|
646
|
-
|
669
|
+
case "create":
|
670
|
+
if len(sys.argv) >= 3:
|
671
|
+
asset_pack_name = " ".join(sys.argv[2:])
|
672
|
+
create_asset_pack(asset_pack_name, pathlib.Path.cwd(), logger=print)
|
673
|
+
return
|
674
|
+
print(HELP_MESSAGE)
|
675
|
+
|
676
|
+
case "pack":
|
677
|
+
if len(sys.argv) == 3:
|
678
|
+
here = pathlib.Path(__file__).absolute().parent
|
679
|
+
start = time.perf_counter()
|
680
|
+
|
681
|
+
if sys.argv[2] == "all":
|
682
|
+
pack_all_asset_packs(
|
683
|
+
here,
|
684
|
+
here / "asset_packs",
|
685
|
+
logger=print,
|
686
|
+
)
|
647
687
|
else:
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
688
|
+
pack_specific(
|
689
|
+
sys.argv[2],
|
690
|
+
pathlib.Path.cwd() / "asset_packs",
|
691
|
+
logger=print,
|
692
|
+
)
|
693
|
+
|
694
|
+
end = time.perf_counter()
|
695
|
+
print(f"\nFinished in {round(end - start, 2)}s\n")
|
696
|
+
return
|
697
|
+
print(HELP_MESSAGE)
|
698
|
+
|
699
|
+
case "recover":
|
700
|
+
if len(sys.argv) == 3:
|
701
|
+
here = pathlib.Path(__file__).absolute().parent
|
702
|
+
start = time.perf_counter()
|
703
|
+
|
704
|
+
if sys.argv[2] == "all":
|
705
|
+
recover_all_asset_packs(
|
706
|
+
here / "asset_packs",
|
707
|
+
here / "recovered",
|
708
|
+
logger=print,
|
709
|
+
)
|
667
710
|
else:
|
668
|
-
|
711
|
+
recover_specific(
|
712
|
+
sys.argv[2],
|
713
|
+
pathlib.Path.cwd() / "recovered",
|
714
|
+
logger=print,
|
715
|
+
)
|
716
|
+
|
717
|
+
end = time.perf_counter()
|
718
|
+
print(f"Finished in {round(end - start, 2)}s")
|
719
|
+
return
|
720
|
+
print(HELP_MESSAGE)
|
669
721
|
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
722
|
+
case "convert":
|
723
|
+
if len(sys.argv) == 3:
|
724
|
+
convert_and_rename_frames_for_all_anims(pathlib.Path(sys.argv[2]) / "Anims", logger=print)
|
725
|
+
return
|
726
|
+
print(HELP_MESSAGE)
|
727
|
+
|
728
|
+
case _:
|
729
|
+
print(HELP_MESSAGE)
|
678
730
|
|
679
731
|
|
680
732
|
if __name__ == "__main__":
|
@@ -1,5 +0,0 @@
|
|
1
|
-
mntm_asset_packer.py,sha256=1oRpiZI7-miamOx0POado6LBBjYo6mIEdfdBVpjltrg,26260
|
2
|
-
mntm_asset_packer-1.1.1.dist-info/METADATA,sha256=AlqTF_5auhg9yNE9XHPH6LjFpR4WFpgbwK-mLb4GjAc,3648
|
3
|
-
mntm_asset_packer-1.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
4
|
-
mntm_asset_packer-1.1.1.dist-info/entry_points.txt,sha256=CF05qVMVPPNhTroKeH_kkKqVgG-mJ-Q0mSAZHpfxkr0,61
|
5
|
-
mntm_asset_packer-1.1.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|