Загрузка данных


import os
import struct

# Папка, куда скрипт сохранит готовые русские файлы игры
OUTPUT_FOLDER = "STCM2L_RUSSIAN"
os.makedirs(OUTPUT_FOLDER, exist_ok=True)

def pack_stcm2l(orig_bin_path, translated_txt_path, output_bin_path):
    if not os.path.exists(orig_bin_path) or not os.path.exists(translated_txt_path):
        return False
        
    with open(orig_bin_path, "rb") as f:
        data = bytearray(f.read())
        
    # Считываем переведенные строки
    translations = []
    with open(translated_txt_path, "r", encoding="utf-8") as t:
        for line in t:
            line = line.strip()
            if line.startswith("[0x") and "]" in line:
                parts = line.split("]", 1)
                offset_hex = parts[0].replace("[", "")
                offset = int(offset_hex, 16)
                text = parts[1].strip()
                translations.append((offset, text))
                
    # Сортируем изменения с конца файла к началу, чтобы сдвиги байт не ломали адреса
    translations.sort(key=lambda x: x[0], reverse=True)
    
    for offset, text in translations:
        # Переводим русский текст в байты (игра обычно требует UTF-8 или Shift-JIS)
        # Если игра со Switch/PC, оставляем utf-8. Если с Vita - смените на shift_jis
        new_bytes = text.encode('utf-8') + b'\x00'
        
        # Определяем длину оригинальной строки в байтах до нулевого терминатора
        orig_len = 0
        while data[offset + orig_len] != 0:
            orig_len += 1
        orig_len += 1 # Включая нулевой байт
        
        # Заменяем старые байты на новые (размер файла изменится, это нормально)
        data[offset : offset + orig_len] = new_bytes
        
        # Автоматический пересчет указателей (Pointers) для движка Otomate
        # Скрипт ищет ссылки на этот текст во всем файле и обновляет их смещение
        diff = len(new_bytes) - orig_len
        if diff != 0:
            # Движок использует 4-байтовые указатели (LE)
            for i in range(0, len(data) - 4, 4):
                val = struct.unpack("<I", data[i:i+4])[0]
                if val > offset:
                    # Если указатель вел на данные после нашей строки, сдвигаем его
                    data[i:i+4] = struct.pack("<I", val + diff)

    with open(output_bin_path, "wb") as out:
        out.write(data)
    return True

# Массовый перебор всей вашей тысячи файлов
total_built = 0
for file_name in os.listdir("."):
    if file_name.endswith(".stcm2l") or file_name.endswith(".DAT"):
        # Ищем текстовый файл с переводом для текущего файла сценария
        txt_name = file_name + ".txt"
        if not os.path.exists(txt_name):
            txt_name = file_name.replace(".stcm2l", ".txt").replace(".DAT", ".txt")
            
        if os.path.exists(txt_name):
            out_name = os.path.join(OUTPUT_FOLDER, file_name)
            if pack_stcm2l(file_name, txt_name, out_name):
                total_built += 1
                print(f"[{total_built}] Успешно собран: {file_name}")

print(f"\nРабота завершена! Собрано файлов: {total_built}. Все они лежат в папке '{OUTPUT_FOLDER}'")