Skip to content

Commit d64e1f7

Browse files
Merge pull request #16 from xcoder-tool/dev
feat(KTX): support for KTX file format and special texture tag
2 parents e5966cf + db359ee commit d64e1f7

26 files changed

+300
-56
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,14 @@
66
/updates/
77
/logs/
88
/CSV/
9+
/TEX/
910
/SC/
1011

1112
# Configuration files
1213
system/config.json
1314

1415
# Python compiled files
1516
*.pyc
17+
18+
# PVRTexToolCLI
19+
PVRTexToolCLI*

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ repos:
1212
rev: 22.12.0
1313
hooks:
1414
- id: black
15-
language_version: python3.10
15+
language_version: python3.11
1616
- repo: https://github.com/charliermarsh/ruff-pre-commit
1717
rev: 'v0.0.261'
1818
hooks:

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ Work with Supercell\`s files on **any** os! SC and CSV are supported for all Sup
3232
- Install loguru using pip;
3333
- In PyDroid open and execute "main.py" file.
3434

35+
### How to enable KTX section
36+
37+
![KTX section demo](docs/KTX section.png)
38+
39+
**Supercell also uses KTX textures in new versions of the games, so it is advisable to perform this step.**
40+
41+
To enable the KTX module, you need to get the "PVRTexToolCLI" binary from the official site: https://developer.imaginationtech.com/pvrtextool/.
42+
43+
Then it is necessary to put CLI in "system/bin/" folder in the main script folder.
44+
3545
### In the plans:
3646
- CSV updating.
3747

docs/KTX section.png

5.53 KB
Loading

system/exceptions/__init__.py

Whitespace-only changes.

system/exceptions/tool_not_found.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class ToolNotFoundException(Exception):
2+
pass

system/languages/en-EU.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@
3434
"decompress_csv_description": "Decompresses spreadsheet file",
3535
"compress_csv_description": "Compresses spreadsheet file",
3636

37+
"ktx_label": "KTX",
38+
"ktx_from_png_label": "PNG2KTX",
39+
"png_from_ktx_label": "KTX2PNG",
40+
"ktx_from_png_description": "Converts PNG to KTX",
41+
"png_from_ktx_description": "Converts KTX to PNG",
42+
3743
"other_features_label": "OTHER",
3844
"check_update": "Check for updates",
3945
"check_for_outdated": "Check for outdated packages",

system/languages/ru-RU.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@
3434
"decompress_csv_description": "Разжимает файл таблиц",
3535
"compress_csv_description": "Сжимает файл таблиц",
3636

37+
"ktx_label": "KTX",
38+
"ktx_from_png_label": "PNG2KTX",
39+
"png_from_ktx_label": "KTX2PNG",
40+
"ktx_from_png_description": "Конвертирует PNG в KTX",
41+
"png_from_ktx_description": "Конвертирует KTX в PNG",
42+
3743
"other_features_label": "ПРОЧЕЕ",
3844
"check_update": "Проверить обновления",
3945
"check_for_outdated": "Проверка устаревших модулей",

system/languages/ua-UA.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@
3434
"decompress_csv_description": "Розпакувати файл таблиці",
3535
"compress_csv_description": "Запакувати файл таблиці",
3636

37+
"ktx_label": "KTX",
38+
"ktx_from_png_label": "PNG2KTX",
39+
"png_from_ktx_label": "KTX2PNG",
40+
"ktx_from_png_description": "Конвертує PNG у KTX",
41+
"png_from_ktx_description": "Конвертує KTX у PNG",
42+
3743
"other_features_label": "ІНШЕ",
3844
"check_update": "Шукати оновлення",
3945
"check_for_outdated": "Шукати застарілі пакети",

system/lib/__init__.py

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,16 @@ def check_files_updated():
6060
def refill_menu():
6161
menu.categories.clear()
6262

63+
sc_category = Menu.Category(0, locale.sc_label)
64+
ktx_category = Menu.Category(1, locale.ktx_label)
65+
csv_category = Menu.Category(2, locale.csv_label)
66+
other = Menu.Category(10, locale.other_features_label)
67+
68+
menu.add_category(sc_category)
69+
menu.add_category(ktx_category)
70+
menu.add_category(csv_category)
71+
menu.add_category(other)
72+
6373
try:
6474
import sc_compression
6575

@@ -86,7 +96,6 @@ def refill_menu():
8696
encode_textures_only,
8797
)
8898

89-
sc_category = Menu.Category(0, locale.sc_label)
9099
sc_category.add(
91100
Menu.Item(
92101
name=locale.decode_sc,
@@ -122,9 +131,29 @@ def refill_menu():
122131
handler=lambda: collect_objects_and_encode(True),
123132
)
124133
)
125-
menu.add_category(sc_category)
126134

127-
csv_category = Menu.Category(1, locale.csv_label)
135+
from system.lib.features.ktx import (
136+
convert_ktx_textures_to_png,
137+
convert_png_textures_to_ktx,
138+
)
139+
from system.lib.pvr_tex_tool import can_use_pvr_tex_tool
140+
141+
if can_use_pvr_tex_tool():
142+
ktx_category.add(
143+
Menu.Item(
144+
name=locale.ktx_from_png_label,
145+
description=locale.ktx_from_png_description,
146+
handler=convert_png_textures_to_ktx,
147+
)
148+
)
149+
ktx_category.add(
150+
Menu.Item(
151+
name=locale.png_from_ktx_label,
152+
description=locale.png_from_ktx_description,
153+
handler=convert_ktx_textures_to_png,
154+
)
155+
)
156+
128157
csv_category.add(
129158
Menu.Item(
130159
name=locale.decompress_csv,
@@ -139,9 +168,7 @@ def refill_menu():
139168
handler=compress_csv,
140169
)
141170
)
142-
menu.add_category(csv_category)
143171

144-
other = Menu.Category(10, locale.other_features_label)
145172
other.add(
146173
Menu.Item(
147174
name=locale.check_update,
@@ -181,4 +208,3 @@ def refill_menu():
181208
)
182209
)
183210
other.add(Menu.Item(name=locale.exit, handler=lambda: (clear(), exit())))
184-
menu.add_category(other)

system/lib/features/csv/compress.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,9 @@ def compress_csv():
1717
try:
1818
with open(f"{folder}/{file}", "rb") as f:
1919
file_data = f.read()
20-
f.close()
2120

2221
with open(f"{folder_export}/{file}", "wb") as f:
2322
f.write(compress(file_data, Signatures.LZMA))
24-
f.close()
2523
except Exception as exception:
2624
logger.exception(
2725
locale.error

system/lib/features/csv/decompress.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,9 @@ def decompress_csv():
1515
try:
1616
with open(f"{folder}/{file}", "rb") as f:
1717
file_data = f.read()
18-
f.close()
1918

2019
with open(f"{folder_export}/{file}", "wb") as f:
2120
f.write(decompress(file_data)[0])
22-
f.close()
2321
except Exception as exception:
2422
logger.exception(
2523
locale.error

system/lib/features/csv/update.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import os
2+
3+
from loguru import logger
4+
from sc_compression import compress
5+
6+
from system.localization import locale
7+
8+
9+
def update_csv():
10+
from sc_compression.signatures import Signatures
11+
12+
input_folder = "./CSV/In-Old"
13+
export_folder = "./CSV/Out-Updated"
14+
15+
for file in os.listdir(input_folder):
16+
if file.endswith(".csv"):
17+
try:
18+
with open(f"{input_folder}/{file}", "rb") as f:
19+
file_data = f.read()
20+
21+
with open(f"{export_folder}/{file}", "wb") as f:
22+
f.write(compress(file_data, Signatures.LZMA))
23+
except Exception as exception:
24+
logger.exception(
25+
locale.error
26+
% (
27+
exception.__class__.__module__,
28+
exception.__class__.__name__,
29+
exception,
30+
)
31+
)
32+
33+
print()

system/lib/features/cut_sprites.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def render_objects(swf: SupercellSWF, output_folder: Path):
2020
# rendered_movie_clip = movie_clip.render(swf)
2121
# if sum(rendered_movie_clip.size) >= 2:
2222
# clip_name = movie_clip.export_name or movie_clip.id
23-
# rendered_movie_clip.save(f"{export_folder}/movie_clips/{clip_name}.png")
23+
# rendered_movie_clip.save(f"{output_folder}/movie_clips/{clip_name}.png")
2424
# else:
2525
# # For debug:
2626
# # logger.warning(f'MovieClip {movie_clip.id} cannot be rendered.')

system/lib/features/directories.py

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,38 @@
11
import os
22
import shutil
33

4+
IO_TYPES = ("In", "Out")
5+
6+
SC_FILE_TYPES = ("Compressed", "Decompressed", "Sprites")
7+
CSV_FILE_TYPES = ("Compressed", "Decompressed")
8+
TEXTURE_FILE_TYPES = ("KTX", "PNG")
9+
10+
11+
def create_directories():
12+
for io_type in IO_TYPES:
13+
for filetype in SC_FILE_TYPES:
14+
os.makedirs(f"SC/{io_type}-{filetype}", exist_ok=True)
15+
16+
for filetype in CSV_FILE_TYPES:
17+
os.makedirs(f"CSV/{io_type}-{filetype}", exist_ok=True)
18+
19+
for filetype in TEXTURE_FILE_TYPES:
20+
os.makedirs(f"TEX/{io_type}-{filetype}", exist_ok=True)
21+
422

523
def clear_directories():
6-
for i in ["In", "Out"]:
7-
for k in ["Compressed", "Decompressed", "Sprites"]:
8-
folder = f"SC/{i}-{k}"
9-
if os.path.isdir(folder):
10-
shutil.rmtree(folder)
11-
os.makedirs(folder, exist_ok=True)
12-
13-
for i in ["In", "Out"]:
14-
for k in ["Compressed", "Decompressed"]:
15-
folder = f"CSV/{i}-{k}"
16-
if os.path.isdir(folder):
17-
shutil.rmtree(folder)
18-
os.makedirs(folder, exist_ok=True)
24+
for io_type in IO_TYPES:
25+
for filetype in SC_FILE_TYPES:
26+
_recreate_directory(f"SC/{io_type}-{filetype}")
27+
28+
for filetype in CSV_FILE_TYPES:
29+
_recreate_directory(f"CSV/{io_type}-{filetype}")
30+
31+
for filetype in TEXTURE_FILE_TYPES:
32+
_recreate_directory(f"TEX/{io_type}-{filetype}")
33+
34+
35+
def _recreate_directory(directory):
36+
if os.path.isdir(directory):
37+
shutil.rmtree(directory)
38+
os.makedirs(directory, exist_ok=True)

system/lib/features/files.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ def open_sc(input_filename: str) -> tuple[bytes, bool]:
3131

3232
with open(input_filename, "rb") as f:
3333
file_data = f.read()
34-
f.close()
3534

3635
try:
3736
if b"START" in file_data:

system/lib/features/initialization.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import os
21
import platform
32

43
from loguru import logger
54

6-
from system import run, clear
5+
from system import clear, run
76
from system.lib import config
7+
from system.lib.features.directories import create_directories
88
from system.lib.features.update.check import get_pip_info, get_tags
99
from system.localization import locale
1010

@@ -30,20 +30,7 @@ def initialize(first_init=False):
3030
else:
3131
logger.info(locale.not_installed % package)
3232
logger.info(locale.crt_workspace)
33-
[
34-
[
35-
os.makedirs(f"SC/{i}-{k}", exist_ok=True)
36-
for k in ["Compressed", "Decompressed", "Sprites"]
37-
]
38-
for i in ["In", "Out"]
39-
]
40-
[
41-
[
42-
os.makedirs(f"CSV/{i}-{k}", exist_ok=True)
43-
for k in ["Compressed", "Decompressed"]
44-
]
45-
for i in ["In", "Out"]
46-
]
33+
create_directories()
4734
logger.info(locale.verifying)
4835

4936
config.initialized = True

system/lib/features/ktx.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import os
2+
from pathlib import Path
3+
4+
from system.lib.pvr_tex_tool import convert_ktx_to_png, convert_png_to_ktx
5+
6+
IN_PNG_PATH = Path("./TEX/In-PNG")
7+
IN_KTX_PATH = Path("./TEX/In-KTX")
8+
OUT_PNG_PATH = Path("./TEX/Out-PNG")
9+
OUT_KTX_PATH = Path("./TEX/Out-KTX")
10+
11+
12+
def convert_png_textures_to_ktx():
13+
input_folder = IN_PNG_PATH
14+
output_folder = OUT_KTX_PATH
15+
16+
for file in os.listdir(input_folder):
17+
if not file.endswith(".png"):
18+
continue
19+
20+
png_filepath = input_folder / file
21+
if not os.path.isfile(png_filepath):
22+
continue
23+
24+
convert_png_to_ktx(png_filepath, output_folder=output_folder)
25+
26+
27+
def convert_ktx_textures_to_png():
28+
input_folder = IN_KTX_PATH
29+
output_folder = OUT_PNG_PATH
30+
31+
for file in os.listdir(input_folder):
32+
if not file.endswith(".ktx"):
33+
continue
34+
35+
ktx_filepath = input_folder / file
36+
if not os.path.isfile(ktx_filepath):
37+
continue
38+
39+
convert_ktx_to_png(ktx_filepath, output_folder=output_folder)

system/lib/features/update/check.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ def get_run_output(command: str):
1919

2020
with open(temp_filename) as f:
2121
file_data = f.read()
22-
f.close()
2322

2423
os.remove(temp_filename)
2524

system/lib/features/update/download.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ def download_update(zip_url):
2626

2727
with open("updates/update.zip", "wb") as f:
2828
f.write(urllib.request.urlopen(zip_url).read())
29-
f.close()
3029

3130
import zipfile
3231

system/lib/menu.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ def choice(self):
7777
self._print_divider_line(console_width)
7878

7979
for category in self.categories:
80+
if len(category.items) == 0:
81+
continue
82+
8083
print_category(category.name)
8184
for item_index in range(len(category.items)):
8285
item = category.items[item_index]

0 commit comments

Comments
 (0)