diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8a85ce1..1dcf347 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,10 +1,10 @@ name: sorting on: push: - branches: [ main ] + branches: [main] paths: - - '_sprites/**' - - 'scripts/**' + - "_sprites/**" + - "scripts/**" permissions: contents: write @@ -14,40 +14,59 @@ jobs: runs-on: ubuntu-latest steps: - - name: checkout - uses: actions/checkout@v4 + - name: checkout + uses: actions/checkout@v4 - - name: setup - uses: actions/setup-node@v4 - with: - node-version: '20' + - name: setup + uses: actions/setup-node@v4 + with: + node-version: "20" - - name: requirments - run: npm ci + - name: requirments + run: npm ci - - name: scripts - working-directory: ./scripts - run: | - rm -rf ../_sprites/unready - npx tsx write.ts - npx tsx sort.ts - npx tsx unready_delete.ts + - name: setup python + uses: actions/setup-python@v5 + with: + python-version: "3.13" - - name: commit changes (exclude sorted) - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git add -A . - git reset _sprites/sorted - git commit -m "actions update" || exit 0 - git push + - name: install python deps + run: | + python -m pip install --upgrade pip + pip install pillow - - name: upload - uses: actions/upload-artifact@v4 - with: - name: sorted - path: ./_sprites/sorted - retention-days: 15 + - name: scripts + working-directory: ./scripts + run: | + rm -rf ../_sprites/unready + npx tsx write.ts + npx tsx sort.ts + npx tsx unready.ts - - name: remove temp sorted folder - run: rm -rf ./_sprites/sorted + - name: commit changes (exclude sorted) + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add -A . + git reset _sprites/sorted + git commit -m "actions update" || exit 0 + git push + + - name: upload + uses: actions/upload-artifact@v4 + with: + name: sorted + path: ./_sprites/sorted + retention-days: 15 + + - name: upload-merged + uses: actions/upload-artifact@v4 + with: + name: sorted + path: ./_sprites/sorted-merged + retention-days: 15 + + - name: remove temp sorted folder + run: | + rm -rf ./_sprites/sorted + rm -rf ./_sprites/sorted-merged diff --git a/_sprites/delete.txt b/_sprites/delete.txt deleted file mode 100644 index 6648dc0..0000000 --- a/_sprites/delete.txt +++ /dev/null @@ -1,11 +0,0 @@ -!! CAUTION !! -Deleting files listed here is IRREVERSIBLE. You won’t be able to restore a deleted file just by removing it from the list. Choose files wisely and don’t regret what you’ve done. -You can still get the files back using Git, but it will be a bit harder. - -To delete a file, write its full path. -Examples: -translation/sp_spr_btrouxls - will delete sprite `sp_spr_btrouxls` in `translation` -original/chapter2/bg_dw_bakery.png - will delete sprite `bg_dw_bakery` in `chapter2` inside `original` - - -DELETE: \ No newline at end of file diff --git a/_sprites/unique.txt b/_sprites/unique.txt index 9621239..e0088f4 100644 --- a/_sprites/unique.txt +++ b/_sprites/unique.txt @@ -1,14 +1,3 @@ -To have a sprite added to the `sorted` folder, you must write its name and chapter in the “UNIQUE FOR SORTING" list! -Examples: -chapter3/img1 – Adds sprite `img1` to the `chapter3` folder (whether it’s an animation folder or just a single sprite) -chapter2/anim2 – Adds sprite `anim2` to the `chapter2` folder (whether it’s an animation folder or just a single sprite) - -If the frame count of an animated sprite differs from the original, you must write its name in the “UNIQUE FRAME COUNT” list! -!! ATTENTION !! -Do this only if the ENTIRE animation of the sprite is different. -If, for example, just one frame is translated and the rest should remain THE SAME, you DO NOT need to add it to the list! - - UNIQUE FOR SORTING: chapter1/spr_blockler_и chapter1/spr_blockler_с diff --git a/scripts/merge.py b/scripts/merge.py new file mode 100755 index 0000000..3d9b950 --- /dev/null +++ b/scripts/merge.py @@ -0,0 +1,60 @@ +import os +import sys +import shutil +from PIL import Image + +in_dir = sys.argv[1] +out_dir = sys.argv[2] + +os.makedirs(in_dir, exist_ok=True) +os.makedirs(out_dir, exist_ok=True) + +sprs = {} + +for item in os.listdir(in_dir): + item_path = os.path.join(in_dir, item) + + if os.path.isfile(item_path) and item.lower().endswith('.png'): + shutil.copy2(item_path, os.path.join(out_dir, item)) + continue + + if not os.path.isdir(item_path): + continue + + frames = [] + for frame_file in os.listdir(item_path): + if not frame_file.lower().endswith('.png'): + continue + + try: + frame_num = int(frame_file.split('_')[-1].split('.')[0]) + frames.append((frame_num, frame_file)) + except (IndexError, ValueError): + continue + + frames.sort(key=lambda x: x[0]) + sprs[item] = [] + + for _, frame_file in frames: + try: + img = Image.open(os.path.join(item_path, frame_file)) + sprs[item].append(img) + except Exception as e: + print(f"Ошибка загрузки {frame_file}: {e}") + +for spr_name, images in sprs.items(): + if not images: + continue + + width = images[0].width + height = images[0].height + total_width = width * len(images) + + sprite_sheet = Image.new('RGBA', (total_width, height)) + + for i, img in enumerate(images): + sprite_sheet.paste(img, (i * width, 0)) + + output_path = os.path.join(out_dir, f"{spr_name}.png") + sprite_sheet.save(output_path) + print(f"Создан: {output_path} ({len(images)} кадров)") \ No newline at end of file diff --git a/scripts/sort.ts b/scripts/sort.ts index cd98f24..7df6989 100644 --- a/scripts/sort.ts +++ b/scripts/sort.ts @@ -1,4 +1,5 @@ import fs from "node:fs"; +import { spawn } from "child_process"; const SPECIALS = ["sp", "spm"]; const DATA = JSON.parse(fs.readFileSync("./data.json", "utf-8")); @@ -19,8 +20,6 @@ UNIQUES_FRAMES?.shift(); while (UNIQUES_NAMES?.at(-1) == "") UNIQUES_NAMES?.pop(); while (UNIQUES_FRAMES?.at(-1) == "") UNIQUES_FRAMES?.pop(); -export const SHARED = UNIQUES_FRAMES; - function add_singles(chapter, sprite_name) { const img_name = `${sprite_name}.png`; if (!fs.existsSync(`../_sprites/translation/${img_name}`)) return; @@ -141,3 +140,11 @@ if (UNIQUES_NAMES != undefined) { ); } } + +for (const chapter of chapters) { + spawn("python3", [ + "merge.py", + `../_sprites/sorted/${chapter}`, + `../_sprites/sorted-merged/${chapter}`, + ]); +} diff --git a/scripts/unready_delete.ts b/scripts/unready.ts similarity index 72% rename from scripts/unready_delete.ts rename to scripts/unready.ts index 1cd8775..97d6b36 100644 --- a/scripts/unready_delete.ts +++ b/scripts/unready.ts @@ -2,30 +2,6 @@ import fs from "node:fs"; const CHAPTERS = JSON.parse(fs.readFileSync("./data.json", "utf-8")); -const DELETE = fs - .readFileSync("../_sprites/delete.txt", "utf-8") - .split("DELETE:") - .at(-1) - ?.split("\n"); - -DELETE?.shift(); -if (DELETE?.at(-1) == "") DELETE?.pop(); - -if (DELETE != undefined) { - for (const del of DELETE) { - if (fs.existsSync(`../_sprites/${del}`)) - fs.rmSync(`../_sprites/${del}`, { - recursive: true, - force: true, - }); - else if (fs.existsSync(`../_sprites/${del}.png`)) - fs.rmSync(`../_sprites/${del}.png`, { - recursive: true, - force: true, - }); - } -} - const UNIQUES = fs .readFileSync("../_sprites/unique.txt", "utf-8") .split("UNIQUE FOR SORTING:")