한글패치 관련 짧은 글들

UnityPy TypeTree 적용 (작성중)

Snowyegret 2023. 9. 15. 19:30

아직 제대로 테스트해보지 않았지만, 일단 기록용으로 작성함.

 

필요 프로그램: TypeTreeGenerator ( https://github.com/K0lb3/TypeTreeGenerator )

 

 

1. 타입트리 생성

TypeTreeGenerator를 다운받아서 {게임명}_data\TypeTreeGenerator 폴더 안에 압축해제한다.

 

import UnityPy
import subprocess
import os


def gen_typetree(game_data_folder, unity_version=None):
    os.makedirs(f"{game_data_folder}/typetree", exist_ok=True)

    dll_folder = f"{game_data_folder}/Managed"
    dll_lst = [i for i in os.listdir(dll_folder) if i.endswith(".dll")]
    ttg_folder = f"{game_data_folder}/TypeTreeGenerator"
    ttg_exe = f"{ttg_folder}/TypeTreeGeneratorCLI.exe"
    for dll in dll_lst:
        cmd = [ttg_exe, "-p", dll_folder, "-a", dll, "-v", unity_version, "-d", "json", "-o", f"{ttg_folder}/typetree_{dll.rstrip('.dll')}.json"]
        try:
            subprocess.run(cmd, check=True)
        except subprocess.CalledProcessError as e:
            print(e)
    return
    
def main():
    game_folder = os.path.dirname(os.path.abspath(__file__))
    env = UnityPy.load(f"{game_folder}/resources.assets")
    gen_typetree(game_folder, env.file.unity_version)

이후, 위 코드를 gen_typetree.py로 저장하고 나서 {게임명}_data 폴더에서 실행하면

{게임명}_data/typetree 폴더 내 dump된 typetree들이 json파일에 담기게 된다.

 

 

2. 타입트리 사용

 

우선, {게임명}_data 폴더 내 Resource 폴더를 복사한 후 폴더명을 Library로 바꾸자.

 

import json
import UnityPy
import os

def load_typetree(fp: str):
    json_lst = [i for i in os.listdir(fp) if i.startswith("typetree_") and i.endswith(".json")]
    load_tree = {}
    for json_file in json_lst:
        clean_fn = os.path.splitext(json_file)[0]
        clean_fn = clean_fn.replace("typetree_", "")
        # clean_fn = clean_fn + ".dll"
        if tree.get(clean_fn) is None:
            load_tree[clean_fn] = {}
        with open(f"{fp}/{json_file}", "r", encoding="utf-8") as f:
            load_tree[clean_fn] = json.load(f)
    return load_tree

def export(fn):
    data_folder = os.path.dirname(os.path.abspath(__file__))
    env = UnityPy.load(fn)
    load_tree = load_typetree(f"{data_folder}/typetree")
    for obj in env.objects:
        if obj.type.name == "MonoBehaviour":
            monobehaviour = obj.read()
            script = monobehaviour.m_Script.read()

            if obj.serialized_type.nodes:
                tree = obj.read_typetree()
            else:
                if script.m_Namespace == "":
                    typetree = load_tree[script.m_AssemblyName][script.m_ClassName]
                else:
                    typetree = load_tree[script.m_AssemblyName][f"{script.m_Namespace}.{script.m_ClassName}"]
                tree = obj.read_typetree(typetree)

            # Tree 작업
            ...

            # 수정한 monobehaviour 저장
            obj.save_typetree(tree)
    
    # 수정한 assets 파일 저장
    with open(f"{fn}_edit", "wb") as f:
        f.write(env.file.save())

if __name__ == "__main__":
    asset_list = ["sharedassets0.assets"] # 임의로 수정
    for i in asset_list:
        export(i)

위 경우 특정 .assets만 작업하기에 그냥 리스트를 만들어서 해당 리스트를 순회하도록 하였다.

UnityPy.load()는 file path, folder path, stream, bytes object를 받아올 수 있으니 임의대로 수정해서 사용하자.

 

또한, script의 m_Namespace가 없는 경우

typetree dump json에서 script.m_ClassName을 Key로 Value를 가져오면 정상적으로 적용이 됐었고,

ex) LabelUI

만약 m_Namespace가 있는 경우 f"{scipt.m_Namespace}.{script.m_ClassName}"을 Key로 Value를 가져오면 정상적으로 적용이 됐었다.

ex) TMPro.TMP_FontAsset

 

 

 

3. 기타등등...

https://github.com/K0lb3/UnityPy/issues/201#issuecomment-1719335452

 

can't read typetree from assets · Issue #201 · K0lb3/UnityPy

Code import UnityPy import json from typing import Dict class FakeNode: def __init__(self, **kwargs): self.__dict__.update(**kwargs) with open("./assembly_typetrees.json", "r", encoding="utf-8") as...

github.com

누군가 Typetree dump 적용에 관해 질문한 글이다.

답변을 보면 특정 클래스로 typetree dump를 읽어오는 것이 보이는데,

아마 답변의 첫번째 방법은 script.m_Namespace가 있는 경우 KeyError를 내면서 적용이 안 될 것이다.

두번째 방법은 잘 모르겠다. 나중에 직접 사용해봐야 알 듯.