Files
novafarma/scripts/complete_reorganization.py
David Kotnik 305c915fc7 🇸🇮 Kompletna reorganizacija v slovensko strukturo
 NAREJENO:
- Scan 1,112 PNG datotek
- Najdenih 109 duplikatov (preskočenih)
- Premaknjenih 635 aktivnih assetov v slovensko strukturo
- Izbrisanih 14 starih angleških map
- Updatanih 11 scriptov za nove poti

📁 NOVA STRUKTURA:
assets/slike/
├── liki/ (karakterji: Kai, Gronk, Ana, NPCs)
├── sovrazniki/ (zombiji, mutanti, bossi)
├── biomi/ (18 zon)
├── zgradbe/ (vse stavbe in props)
├── predmeti/ (orodja, semena, hrana)
├── orozje/ (hladno, strelno)
├── rastline/ (posevki, drevesa)
├── ui/ (interface elementi)
├── efekti/ (voda, dim)
└── cutscene/ (flashbacki)

💡 ADHD-FRIENDLY:
- Slovensko poimenovanje
- Max 2 nivoja podmap
- Logična kategorizacija
- Enostavno iskanje
2025-12-31 01:54:16 +01:00

394 lines
15 KiB
Python

#!/usr/bin/env python3
"""
🇸🇮 KOMPLEKNA REORGANIZACIJA ASSETOV - SLOVENSKO
1. Scan za duplikate (iste slike)
2. Scan za neuporabljene slike
3. Premakni vse v slovenske mape
4. Izbriši stare angleške mape
5. Update vse skripte
NOVA STRUKTURA (SLOVENSKO):
assets/slike/
├── liki/ (protagonisti)
├── sovrazniki/ (zombiji, mutanti, bossi)
├── biomi/ (18 zon)
├── zgradbe/ (stavbe)
├── predmeti/ (tools, seeds, food)
├── orozje/ (weapons)
├── rastline/ (crops, trees, plants)
├── ui/ (interface)
├── efekti/ (effects)
└── cutscene/ (flashbacks)
"""
import hashlib
import shutil
import re
from pathlib import Path
from collections import defaultdict
from typing import Dict, List, Set
# Paths
REPO = Path("/Users/davidkotnik/repos/novafarma")
OLD_ASSETS = REPO / "assets/images"
NEW_ASSETS = REPO / "assets/slike"
SRC_DIR = REPO / "src"
# Mapping: OLD → NEW
MAPPING = {
"characters": "liki",
"enemies": "sovrazniki",
"biomes": "biomi",
"buildings": "zgradbe",
"items": "predmeti",
"weapons": "orozje",
"plants": "rastline",
"crops": "rastline", # merge crops into rastline
"ui": "ui",
"effects": "efekti",
"cutscenes": "cutscene",
"environment": "rastline", # trees, rocks → rastline
"props": "zgradbe", # props → zgradbe (campfire, etc)
"bosses": "sovrazniki", # bosses → sovrazniki
"mutanti": "sovrazniki", # mutanti → sovrazniki
"zivali": "rastline", # animals → rastline
"npcs": "liki", # npcs → liki
"workstations": "zgradbe",
}
class AssetReorganizer:
def __init__(self):
self.duplicates: Dict[str, List[Path]] = defaultdict(list)
self.file_hashes: Dict[str, Path] = {}
self.all_pngs: List[Path] = []
self.used_assets: Set[str] = set()
self.stats = {
"total_files": 0,
"duplicates": 0,
"unused": 0,
"migrated": 0,
"deleted": 0,
}
def calculate_hash(self, filepath: Path) -> str:
"""Calculate MD5 hash of file."""
hash_md5 = hashlib.md5()
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
def scan_duplicates(self):
"""Find duplicate images by content hash."""
print("🔍 Scanning for duplicate images...")
self.all_pngs = list(OLD_ASSETS.rglob("*.png"))
self.stats["total_files"] = len(self.all_pngs)
print(f" Found {len(self.all_pngs)} PNG files")
for filepath in self.all_pngs:
file_hash = self.calculate_hash(filepath)
if file_hash in self.file_hashes:
# Duplicate found!
original = self.file_hashes[file_hash]
self.duplicates[file_hash].append(filepath)
print(f" 🔴 DUPLICATE: {filepath.name}")
print(f" → Same as: {original.name}")
else:
self.file_hashes[file_hash] = filepath
print(f"\n ✅ Found {len(self.duplicates)} duplicate groups\n")
self.stats["duplicates"] = sum(len(files) for files in self.duplicates.values())
def scan_code_references(self):
"""Scan source code for asset references."""
print("🔍 Scanning code for asset usage...")
# Patterns to match asset references
patterns = [
r'["\']([^"\']*\.png)["\']', # "filename.png"
r'load\.image\(["\']([^"\']+)["\']', # Phaser load.image
r'assets/images/([^"\']+\.png)', # Direct path references
]
code_files = list(SRC_DIR.rglob("*.js")) + list(REPO.glob("*.js"))
for code_file in code_files:
try:
content = code_file.read_text(encoding='utf-8')
for pattern in patterns:
matches = re.findall(pattern, content)
for match in matches:
# Extract just the filename
filename = Path(match).name
self.used_assets.add(filename)
except Exception as e:
print(f" ⚠️ Could not read {code_file.name}: {e}")
print(f" ✅ Found {len(self.used_assets)} referenced assets\n")
def find_unused(self):
"""Find PNG files not referenced in code."""
print("🔍 Finding unused assets...")
unused = []
for filepath in self.all_pngs:
if filepath.name not in self.used_assets:
# Also check without timestamps/suffixes
base_name = re.sub(r'_\d{13,}\.png$', '.png', filepath.name)
base_name = re.sub(r'_(styleA|styleB|original|sprite|preview)_.*\.png$', '.png', base_name)
if base_name not in self.used_assets and filepath.name not in self.used_assets:
unused.append(filepath)
self.stats["unused"] = len(unused)
print(f" ⚠️ Found {len(unused)} potentially unused files\n")
return unused
def create_slovenian_structure(self):
"""Create new Slovenian folder structure."""
print("📁 Creating Slovenian folder structure...")
folders = [
"liki/kai",
"liki/gronk",
"liki/ana",
"liki/grok",
"liki/npcs",
"sovrazniki/zombiji",
"sovrazniki/mutanti",
"sovrazniki/bossi",
"biomi/01_dolina_farm",
"biomi/02_temni_gozd",
"biomi/03_zapusceno_mesto",
"zgradbe",
"predmeti/orodja",
"predmeti/semena",
"predmeti/hrana",
"orozje/hladno", # melee
"orozje/strelno", # ranged
"rastline/posevki",
"rastline/drevesa",
"ui",
"efekti/voda",
"efekti/dim",
"cutscene",
]
for folder in folders:
path = NEW_ASSETS / folder
path.mkdir(parents=True, exist_ok=True)
print(f"{folder}/")
print()
def migrate_assets(self, delete_duplicates=False, delete_unused=False):
"""Migrate all assets to new structure."""
print("🚚 Migrating assets to Slovenian structure...")
# Get list of files to skip (duplicates + unused)
skip_files = set()
if delete_duplicates:
for dup_list in self.duplicates.values():
# Keep first, delete rest
skip_files.update(dup_list)
if delete_unused:
unused = self.find_unused()
skip_files.update(unused)
# Migrate each category
for old_name, new_name in MAPPING.items():
old_path = OLD_ASSETS / old_name
if not old_path.exists():
continue
print(f"\n📦 {old_name}/ → {new_name}/")
# Find all PNGs in this category
png_files = list(old_path.rglob("*.png"))
for src_file in png_files:
if src_file in skip_files:
print(f" ⏭️ SKIP: {src_file.name} (duplicate/unused)")
continue
# Determine target based on filename
target_dir = NEW_ASSETS / new_name
# Sub-categorization
if new_name == "liki":
if "kai_" in src_file.name.lower():
target_dir = NEW_ASSETS / "liki/kai"
elif "gronk_" in src_file.name.lower():
target_dir = NEW_ASSETS / "liki/gronk"
elif "ana_" in src_file.name.lower():
target_dir = NEW_ASSETS / "liki/ana"
elif "npc_" in src_file.name.lower():
target_dir = NEW_ASSETS / "liki/npcs"
elif new_name == "sovrazniki":
if "zombie_" in src_file.name.lower():
target_dir = NEW_ASSETS / "sovrazniki/zombiji"
elif "mutant_" in src_file.name.lower():
target_dir = NEW_ASSETS / "sovrazniki/mutanti"
elif "boss_" in src_file.name.lower():
target_dir = NEW_ASSETS / "sovrazniki/bossi"
elif new_name == "rastline":
if "wheat_" in src_file.name.lower() or "crop_" in src_file.name.lower():
target_dir = NEW_ASSETS / "rastline/posevki"
elif "tree_" in src_file.name.lower() or "oak_" in src_file.name.lower():
target_dir = NEW_ASSETS / "rastline/drevesa"
elif new_name == "predmeti":
if "hoe_" in src_file.name.lower() or "axe_" in src_file.name.lower() or "watering" in src_file.name.lower():
target_dir = NEW_ASSETS / "predmeti/orodja"
elif "seed" in src_file.name.lower():
target_dir = NEW_ASSETS / "predmeti/semena"
elif new_name == "efekti":
if "water_" in src_file.name.lower():
target_dir = NEW_ASSETS / "efekti/voda"
target_dir.mkdir(parents=True, exist_ok=True)
dest_file = target_dir / src_file.name
try:
shutil.copy2(src_file, dest_file)
print(f"{src_file.name}")
self.stats["migrated"] += 1
except Exception as e:
print(f"{src_file.name}: {e}")
# Also migrate demo/ folder
demo_path = OLD_ASSETS / "demo"
if demo_path.exists():
print(f"\n📦 demo/ → (various Slovenian folders)")
self._migrate_demo_folder(demo_path, skip_files)
def _migrate_demo_folder(self, demo_path: Path, skip_files: Set[Path]):
"""Migrate demo folder to appropriate Slovenian locations."""
for src_file in demo_path.rglob("*.png"):
if src_file in skip_files:
continue
# Classify by filename
filename_lower = src_file.name.lower()
if "kai_" in filename_lower:
target = NEW_ASSETS / "liki/kai" / src_file.name
elif "zombie_" in filename_lower:
target = NEW_ASSETS / "sovrazniki/zombiji" / src_file.name
elif "wheat_" in filename_lower:
target = NEW_ASSETS / "rastline/posevki" / src_file.name
elif "tree_" in filename_lower or "oak_" in filename_lower:
target = NEW_ASSETS / "rastline/drevesa" / src_file.name
elif "grass_" in filename_lower or "dirt_" in filename_lower or "stone_path" in filename_lower:
target = NEW_ASSETS / "biomi/01_dolina_farm" / src_file.name
elif "shack" in filename_lower or "barn" in filename_lower or "tent" in filename_lower:
target = NEW_ASSETS / "zgradbe" / src_file.name
elif "water_anim" in filename_lower:
target = NEW_ASSETS / "efekti/voda" / src_file.name
elif "ui_" in filename_lower:
target = NEW_ASSETS / "ui" / src_file.name
else:
target = NEW_ASSETS / "ostalo" / src_file.name
target.parent.mkdir(parents=True, exist_ok=True)
try:
shutil.copy2(src_file, target)
print(f"{src_file.name}")
self.stats["migrated"] += 1
except Exception as e:
print(f"{src_file.name}: {e}")
def cleanup_old_folders(self):
"""Remove old English folders (after migration)."""
print("\n🗑️ Removing old English folders...")
old_folders = [
"characters", "enemies", "buildings", "items", "weapons",
"plants", "crops", "environment", "props", "bosses",
"mutanti", "zivali", "npcs", "workstations", "demo",
"demo_originals_with_white_bg"
]
for folder_name in old_folders:
folder_path = OLD_ASSETS / folder_name
if folder_path.exists() and folder_path.is_dir():
try:
shutil.rmtree(folder_path)
print(f" 🗑️ Deleted: {folder_name}/")
except Exception as e:
print(f" ❌ Could not delete {folder_name}/: {e}")
def generate_report(self):
"""Generate final report."""
print("\n" + "="*70)
print("📊 REORGANIZATION COMPLETE!")
print("="*70)
print(f" Total files scanned: {self.stats['total_files']:4d}")
print(f" Duplicates found: {self.stats['duplicates']:4d}")
print(f" Unused files: {self.stats['unused']:4d}")
print(f" Files migrated: {self.stats['migrated']:4d}")
print("="*70)
print("\n✅ Nova struktura: assets/slike/")
print(" 📂 liki/")
print(" 📂 sovrazniki/")
print(" 📂 biomi/")
print(" 📂 zgradbe/")
print(" 📂 predmeti/")
print(" 📂 orozje/")
print(" 📂 rastline/")
print(" 📂 ui/")
print(" 📂 efekti/")
print(" 📂 cutscene/")
print("="*70)
def main():
print("="*70)
print("🇸🇮 KOMPLEKNA REORGANIZACIJA - SLOVENSKO")
print("="*70)
reorganizer = AssetReorganizer()
# Step 1: Scan duplicates
reorganizer.scan_duplicates()
# Step 2: Scan code
reorganizer.scan_code_references()
# Step 3: Find unused
reorganizer.find_unused()
# Step 4: Create new structure
reorganizer.create_slovenian_structure()
# Step 5: Migrate (with cleanup)
reorganizer.migrate_assets(
delete_duplicates=True, # Skip duplicates
delete_unused=False # Keep unused for now (manual review)
)
# Step 6: Cleanup old folders
reorganizer.cleanup_old_folders()
# Step 7: Report
reorganizer.generate_report()
print("\n📝 NASLEDNJI KORAKI:")
print(" 1. git status # Preglej spremembe")
print(" 2. Preveri da vse deluje")
print(" 3. git add -A && git commit -m '🇸🇮 Reorganizacija v slovensko strukturo'")
if __name__ == "__main__":
main()