Download app.py from Cnass/UnityPy: direct link, hf CLI and curl.
- Browser
- Download file 7.19 kB
-
https://huggingface.co/spaces/Cnass/UnityPy/resolve/189ca4e8ddec1285e6166580765c14f8db7d6f38/app.py
- Command line
-
hf download hf://spaces/Cnass/UnityPy@189ca4e8ddec1285e6166580765c14f8db7d6f38/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Cnass/UnityPy/resolve/189ca4e8ddec1285e6166580765c14f8db7d6f38/app.py
7.19 kB
| import os | |
| import zipfile | |
| import tempfile | |
| import json | |
| import re | |
| import subprocess | |
| import UnityPy | |
| from fastapi import FastAPI, UploadFile, File | |
| from fastapi.responses import FileResponse | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from typing import Optional | |
| app = FastAPI() | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| async def generate_dll(binary_file: UploadFile = File(...), metadata_file: UploadFile = File(...)): | |
| temp_dir = tempfile.mkdtemp() | |
| binary_path = os.path.join(temp_dir, binary_file.filename) | |
| metadata_path = os.path.join(temp_dir, metadata_file.filename) | |
| with open(binary_path, "wb") as f: f.write(await binary_file.read()) | |
| with open(metadata_path, "wb") as f: f.write(await metadata_file.read()) | |
| output_dir = os.path.join(temp_dir, "output") | |
| os.makedirs(output_dir, exist_ok=True) | |
| subprocess.run(["/app/dumper/Il2CppDumper", binary_path, metadata_path, output_dir], capture_output=True) | |
| zip_path = os.path.join(temp_dir, "DummyDlls.zip") | |
| with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf: | |
| for root, _, files in os.walk(output_dir): | |
| for file in files: | |
| if file.endswith(".dll"): zipf.write(os.path.join(root, file), arcname=file) | |
| return FileResponse(zip_path, media_type="application/zip", filename="DummyDlls.zip") | |
| async def extract_dialogues(file: UploadFile = File(...), assembly_file: Optional[UploadFile] = File(None)): | |
| temp_dir = tempfile.mkdtemp() | |
| asset_path = os.path.join(temp_dir, file.filename) | |
| with open(asset_path, "wb") as f: f.write(await file.read()) | |
| env = UnityPy.load(asset_path) | |
| zip_filename = os.path.join(temp_dir, f"{file.filename}_dialogues.zip") | |
| extracted_count = 0 | |
| with zipfile.ZipFile(zip_filename, 'w', zipfile.ZIP_DEFLATED) as zipf: | |
| for obj in env.objects: | |
| if obj.type.name in ["TextAsset", "MonoBehaviour"]: | |
| # Dosya ismini geri paketlerken tanıyabilmemiz için ID'yi garanti altına alıyoruz | |
| obj_name = f"{obj.type.name}_{obj.path_id}" | |
| if obj.type.name == "MonoBehaviour": | |
| raw_data = obj.get_raw_data() | |
| found_strings = {} | |
| i = 28 | |
| while i <= len(raw_data) - 4: | |
| length = int.from_bytes(raw_data[i:i+4], 'little') | |
| if 2 <= length <= 5000 and (i + 4 + length) <= len(raw_data): | |
| str_bytes = raw_data[i+4 : i+4+length] | |
| pad_len = (4 - (length % 4)) % 4 | |
| if (i + 4 + length + pad_len) <= len(raw_data): | |
| padding = raw_data[i+4+length : i+4+length+pad_len] | |
| if all(b == 0 for b in padding): | |
| try: | |
| text = str_bytes.decode('utf-8') | |
| if len(text.strip()) > 1 and any(c.isalpha() for c in text): | |
| found_strings[text] = text | |
| i += 4 + length + pad_len | |
| continue | |
| except UnicodeDecodeError: | |
| pass | |
| i += 4 | |
| if found_strings: | |
| zipf.writestr(f"{obj_name}_raw.json", json.dumps(found_strings, indent=4, ensure_ascii=False).encode('utf-8')) | |
| extracted_count += 1 | |
| elif obj.type.name == "TextAsset": | |
| try: | |
| content = obj.read().text.encode('utf-8') | |
| zipf.writestr(f"{obj_name}.txt", content) | |
| extracted_count += 1 | |
| except: pass | |
| return FileResponse(zip_filename, media_type="application/zip", filename=f"{file.filename}_dialogues.zip") | |
| async def repack_dialogues(asset_file: UploadFile = File(...), mod_zip: UploadFile = File(...)): | |
| temp_dir = tempfile.mkdtemp() | |
| asset_path = os.path.join(temp_dir, asset_file.filename) | |
| zip_path = os.path.join(temp_dir, mod_zip.filename) | |
| with open(asset_path, "wb") as f: f.write(await asset_file.read()) | |
| with open(zip_path, "wb") as f: f.write(await mod_zip.read()) | |
| # DİNAMİK PAKETLEME VE IŞIK HIZINDA O(1) ALGORİTMASI | |
| env = UnityPy.load(asset_path) | |
| # 1. Zip'in içindeki çevirileri ID'lerine göre hafızaya al (Hız Aşırtma) | |
| path_id_to_translations = {} | |
| with zipfile.ZipFile(zip_path, 'r') as zipf: | |
| for file_info in zipf.infolist(): | |
| filename = file_info.filename | |
| if filename.endswith(".json"): | |
| # Regex ile dosya isminden ID'yi güvenle kopar | |
| match = re.search(r'_(\d+)(_raw)?\.json$', filename) | |
| if match: | |
| path_id = int(match.group(1)) | |
| content = zipf.read(filename) | |
| path_id_to_translations[path_id] = json.loads(content.decode('utf-8')) | |
| # 2. Oyun dosyasını sadece BİR KERE tara (Zaman Aşımını Kırar) | |
| for obj in env.objects: | |
| if obj.path_id in path_id_to_translations: | |
| translations = path_id_to_translations[obj.path_id] | |
| if obj.type.name == "MonoBehaviour": | |
| raw_data = obj.get_raw_data() | |
| patched_data = bytearray(raw_data) | |
| for orig_str, trans_str in translations.items(): | |
| if orig_str == trans_str: continue | |
| # Orijinal metnin tam Binary (İkili) haritasını çıkar | |
| orig_bytes = orig_str.encode('utf-8') | |
| orig_pad = (4 - (len(orig_bytes) % 4)) % 4 | |
| orig_block = len(orig_bytes).to_bytes(4, 'little') + orig_bytes + (b'\x00' * orig_pad) | |
| # Çevrilmiş YENİ metnin (uzunluğu fark etmeksizin) Binary haritasını çıkar | |
| trans_bytes = trans_str.encode('utf-8') | |
| trans_pad = (4 - (len(trans_bytes) % 4)) % 4 | |
| trans_block = len(trans_bytes).to_bytes(4, 'little') + trans_bytes + (b'\x00' * trans_pad) | |
| # Bloğu değiştir (Eski sınırlar kalktı!) | |
| patched_data = patched_data.replace(orig_block, trans_block) | |
| # Değişmiş veriyi kaydet (UnityPy burada POINTER REBUILD yapar!) | |
| obj.set_raw_data(bytes(patched_data)) | |
| # 3. Dosyayı Kaydet | |
| output_path = os.path.join(temp_dir, f"repacked_{asset_file.filename}") | |
| with open(output_path, "wb") as f: f.write(env.file.save()) | |
| return FileResponse(output_path, media_type="application/octet-stream", filename=asset_file.filename) | |