Cnass commited on
Commit
189ca4e
·
verified ·
1 Parent(s): 29679c0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +48 -57
app.py CHANGED
@@ -2,6 +2,7 @@ import os
2
  import zipfile
3
  import tempfile
4
  import json
 
5
  import subprocess
6
  import UnityPy
7
  from fastapi import FastAPI, UploadFile, File
@@ -21,7 +22,6 @@ app.add_middleware(
21
 
22
  @app.post("/generate_dll")
23
  async def generate_dll(binary_file: UploadFile = File(...), metadata_file: UploadFile = File(...)):
24
- # Bu adımı değiştirmedik, DummyDll üretmek isteyenler için sağlam duruyor
25
  temp_dir = tempfile.mkdtemp()
26
  binary_path = os.path.join(temp_dir, binary_file.filename)
27
  metadata_path = os.path.join(temp_dir, metadata_file.filename)
@@ -46,112 +46,103 @@ async def extract_dialogues(file: UploadFile = File(...), assembly_file: Optiona
46
  env = UnityPy.load(asset_path)
47
  zip_filename = os.path.join(temp_dir, f"{file.filename}_dialogues.zip")
48
  extracted_count = 0
49
- log_content = ["=== UNITYPY İKİLİ (BINARY) İŞLEM RAPORU ==="]
50
 
51
  with zipfile.ZipFile(zip_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
52
  for obj in env.objects:
53
  if obj.type.name in ["TextAsset", "MonoBehaviour"]:
54
- # Dosya adını güvenli şekilde al
55
  obj_name = f"{obj.type.name}_{obj.path_id}"
56
- try:
57
- data = obj.read()
58
- if hasattr(data, "name") and data.name: obj_name = data.name
59
- except: pass
60
 
61
- log_content.append(f"\nİnceleniyor: {obj.type.name} (ID: {obj.path_id})")
62
-
63
- if obj.type.name == "TextAsset":
64
- try:
65
- content = obj.read().text.encode('utf-8')
66
- zipf.writestr(f"{obj_name}.txt", content)
67
- extracted_count += 1
68
- log_content.append(f" -> Başarılı: {obj_name}.txt oluşturuldu.")
69
- except: pass
70
-
71
- elif obj.type.name == "MonoBehaviour":
72
- # TİP AĞACI ÇÖKERSE DOĞRUDAN HAM BELLEK TARAMASI YAP
73
  raw_data = obj.get_raw_data()
74
  found_strings = {}
75
- i = 28 # MonoBehaviour ana başlığını atla
76
 
77
  while i <= len(raw_data) - 4:
78
  length = int.from_bytes(raw_data[i:i+4], 'little')
79
- # Mantıklı bir metin uzunluğu arıyoruz (2 ile 5000 karakter arası)
80
  if 2 <= length <= 5000 and (i + 4 + length) <= len(raw_data):
81
  str_bytes = raw_data[i+4 : i+4+length]
82
  pad_len = (4 - (length % 4)) % 4
83
 
84
- # Padding (Boşluk) kontrolü
85
  if (i + 4 + length + pad_len) <= len(raw_data):
86
  padding = raw_data[i+4+length : i+4+length+pad_len]
87
  if all(b == 0 for b in padding):
88
  try:
89
  text = str_bytes.decode('utf-8')
90
- # Metin sadece sayılardan veya bozuk sembollerden oluşmuyorsa al
91
  if len(text.strip()) > 1 and any(c.isalpha() for c in text):
92
  found_strings[text] = text
93
  i += 4 + length + pad_len
94
  continue
95
  except UnicodeDecodeError:
96
  pass
97
- i += 4 # Unity bayt dizilimleri her zaman 4'ün katıdır
98
 
99
  if found_strings:
100
  zipf.writestr(f"{obj_name}_raw.json", json.dumps(found_strings, indent=4, ensure_ascii=False).encode('utf-8'))
101
  extracted_count += 1
102
- log_content.append(f" -> BİNARY BAŞARISI: {obj_name}_raw.json ({len(found_strings)} metin bulundu)")
103
- else:
104
- log_content.append(f" -> Atlandı: Bellekte metin bulunamadı.")
105
-
106
- if extracted_count == 0: log_content.append("\nSONUÇ: Hedef dosyada metin bulunamadı.")
107
- zipf.writestr("islem_raporu.txt", "\n".join(log_content).encode('utf-8'))
 
108
 
109
  return FileResponse(zip_filename, media_type="application/zip", filename=f"{file.filename}_dialogues.zip")
110
- # app.py'nin son kısmındaki repack fonksiyonunu bu şekilde güncelle:
111
  @app.post("/repack")
112
  async def repack_dialogues(asset_file: UploadFile = File(...), mod_zip: UploadFile = File(...)):
113
- # Geçici dosyaları tanımla
114
  temp_dir = tempfile.mkdtemp()
115
  asset_path = os.path.join(temp_dir, asset_file.filename)
116
  zip_path = os.path.join(temp_dir, mod_zip.filename)
117
-
118
  with open(asset_path, "wb") as f: f.write(await asset_file.read())
119
  with open(zip_path, "wb") as f: f.write(await mod_zip.read())
120
 
121
- # Paketi yükle
122
  env = UnityPy.load(asset_path)
123
 
 
 
124
  with zipfile.ZipFile(zip_path, 'r') as zipf:
125
  for file_info in zipf.infolist():
126
  filename = file_info.filename
127
- content = zipf.read(filename)
 
 
 
 
 
 
 
 
 
 
 
128
 
129
- for obj in env.objects:
130
- obj_name = f"{obj.type.name}_{obj.path_id}"
131
- try:
132
- if hasattr(obj.read(), "name") and obj.read().name: obj_name = obj.read().name
133
- except: pass
134
 
135
- # Sadece _raw.json olanları işle (Binary Patching)
136
- if obj.type.name == "MonoBehaviour" and filename == f"{obj_name}_raw.json":
137
- translations = json.loads(content.decode('utf-8'))
138
- raw_data = obj.get_raw_data()
139
- patched_data = bytearray(raw_data)
140
 
141
- for orig_str, trans_str in translations.items():
142
- if orig_str == trans_str: continue
143
- orig_bytes = orig_str.encode('utf-8')
144
- trans_bytes = trans_str.encode('utf-8')
145
-
146
- # Basit bayt değiştirme (Kapsayıcıyı bozmadan yama)
147
- # Eğer çeviri daha uzunsa dosyayı bozabilir, bu yüzden sadece aynı uzunlukta ise değiştir
148
- if len(trans_bytes) <= len(orig_bytes):
149
- patched_data = patched_data.replace(orig_bytes, trans_bytes.ljust(len(orig_bytes), b'\x00'))
150
 
151
- obj.set_raw_data(bytes(patched_data))
152
- break
 
 
 
 
 
 
 
 
153
 
154
- # Paketle ve kaydet (Daha hızlı yazma için optimize edilmiş)
155
  output_path = os.path.join(temp_dir, f"repacked_{asset_file.filename}")
156
  with open(output_path, "wb") as f: f.write(env.file.save())
157
 
 
2
  import zipfile
3
  import tempfile
4
  import json
5
+ import re
6
  import subprocess
7
  import UnityPy
8
  from fastapi import FastAPI, UploadFile, File
 
22
 
23
  @app.post("/generate_dll")
24
  async def generate_dll(binary_file: UploadFile = File(...), metadata_file: UploadFile = File(...)):
 
25
  temp_dir = tempfile.mkdtemp()
26
  binary_path = os.path.join(temp_dir, binary_file.filename)
27
  metadata_path = os.path.join(temp_dir, metadata_file.filename)
 
46
  env = UnityPy.load(asset_path)
47
  zip_filename = os.path.join(temp_dir, f"{file.filename}_dialogues.zip")
48
  extracted_count = 0
 
49
 
50
  with zipfile.ZipFile(zip_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
51
  for obj in env.objects:
52
  if obj.type.name in ["TextAsset", "MonoBehaviour"]:
53
+ # Dosya ismini geri paketlerken tanıyabilmemiz için ID'yi garanti altına alıyoruz
54
  obj_name = f"{obj.type.name}_{obj.path_id}"
 
 
 
 
55
 
56
+ if obj.type.name == "MonoBehaviour":
 
 
 
 
 
 
 
 
 
 
 
57
  raw_data = obj.get_raw_data()
58
  found_strings = {}
59
+ i = 28
60
 
61
  while i <= len(raw_data) - 4:
62
  length = int.from_bytes(raw_data[i:i+4], 'little')
 
63
  if 2 <= length <= 5000 and (i + 4 + length) <= len(raw_data):
64
  str_bytes = raw_data[i+4 : i+4+length]
65
  pad_len = (4 - (length % 4)) % 4
66
 
 
67
  if (i + 4 + length + pad_len) <= len(raw_data):
68
  padding = raw_data[i+4+length : i+4+length+pad_len]
69
  if all(b == 0 for b in padding):
70
  try:
71
  text = str_bytes.decode('utf-8')
 
72
  if len(text.strip()) > 1 and any(c.isalpha() for c in text):
73
  found_strings[text] = text
74
  i += 4 + length + pad_len
75
  continue
76
  except UnicodeDecodeError:
77
  pass
78
+ i += 4
79
 
80
  if found_strings:
81
  zipf.writestr(f"{obj_name}_raw.json", json.dumps(found_strings, indent=4, ensure_ascii=False).encode('utf-8'))
82
  extracted_count += 1
83
+
84
+ elif obj.type.name == "TextAsset":
85
+ try:
86
+ content = obj.read().text.encode('utf-8')
87
+ zipf.writestr(f"{obj_name}.txt", content)
88
+ extracted_count += 1
89
+ except: pass
90
 
91
  return FileResponse(zip_filename, media_type="application/zip", filename=f"{file.filename}_dialogues.zip")
92
+
93
  @app.post("/repack")
94
  async def repack_dialogues(asset_file: UploadFile = File(...), mod_zip: UploadFile = File(...)):
 
95
  temp_dir = tempfile.mkdtemp()
96
  asset_path = os.path.join(temp_dir, asset_file.filename)
97
  zip_path = os.path.join(temp_dir, mod_zip.filename)
 
98
  with open(asset_path, "wb") as f: f.write(await asset_file.read())
99
  with open(zip_path, "wb") as f: f.write(await mod_zip.read())
100
 
101
+ # DİNAMİK PAKETLEME VE IŞIK HIZINDA O(1) ALGORİTMASI
102
  env = UnityPy.load(asset_path)
103
 
104
+ # 1. Zip'in içindeki çevirileri ID'lerine göre hafızaya al (Hız Aşırtma)
105
+ path_id_to_translations = {}
106
  with zipfile.ZipFile(zip_path, 'r') as zipf:
107
  for file_info in zipf.infolist():
108
  filename = file_info.filename
109
+ if filename.endswith(".json"):
110
+ # Regex ile dosya isminden ID'yi güvenle kopar
111
+ match = re.search(r'_(\d+)(_raw)?\.json$', filename)
112
+ if match:
113
+ path_id = int(match.group(1))
114
+ content = zipf.read(filename)
115
+ path_id_to_translations[path_id] = json.loads(content.decode('utf-8'))
116
+
117
+ # 2. Oyun dosyasını sadece BİR KERE tara (Zaman Aşımını Kırar)
118
+ for obj in env.objects:
119
+ if obj.path_id in path_id_to_translations:
120
+ translations = path_id_to_translations[obj.path_id]
121
 
122
+ if obj.type.name == "MonoBehaviour":
123
+ raw_data = obj.get_raw_data()
124
+ patched_data = bytearray(raw_data)
 
 
125
 
126
+ for orig_str, trans_str in translations.items():
127
+ if orig_str == trans_str: continue
 
 
 
128
 
129
+ # Orijinal metnin tam Binary (İkili) haritasını çıkar
130
+ orig_bytes = orig_str.encode('utf-8')
131
+ orig_pad = (4 - (len(orig_bytes) % 4)) % 4
132
+ orig_block = len(orig_bytes).to_bytes(4, 'little') + orig_bytes + (b'\x00' * orig_pad)
 
 
 
 
 
133
 
134
+ # Çevrilmiş YENİ metnin (uzunluğu fark etmeksizin) Binary haritasını çıkar
135
+ trans_bytes = trans_str.encode('utf-8')
136
+ trans_pad = (4 - (len(trans_bytes) % 4)) % 4
137
+ trans_block = len(trans_bytes).to_bytes(4, 'little') + trans_bytes + (b'\x00' * trans_pad)
138
+
139
+ # Bloğu değiştir (Eski sınırlar kalktı!)
140
+ patched_data = patched_data.replace(orig_block, trans_block)
141
+
142
+ # Değişmiş veriyi kaydet (UnityPy burada POINTER REBUILD yapar!)
143
+ obj.set_raw_data(bytes(patched_data))
144
 
145
+ # 3. Dosyayı Kaydet
146
  output_path = os.path.join(temp_dir, f"repacked_{asset_file.filename}")
147
  with open(output_path, "wb") as f: f.write(env.file.save())
148