Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 60 additions & 1 deletion UnityPy/classes/generated.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from __future__ import annotations

from abc import ABC
from typing import List, Optional, Tuple, TypeVar, Union
from typing import List, Optional, Tuple, TypeVar, Union, TYPE_CHECKING

from attrs import define as attrs_define

Expand Down Expand Up @@ -2041,6 +2041,10 @@ class Pipeline(Component):
class Renderer(Component):
m_GameObject: PPtr[GameObject]

if TYPE_CHECKING:
from .legacy_patch.Renderer import export as _export
export = _export


@unitypy_define
class BillboardRenderer(Renderer):
Expand Down Expand Up @@ -2744,6 +2748,32 @@ class GameObject(EditorExtension):
m_Name: str
m_Tag: int

if TYPE_CHECKING:
from .legacy_patch.GameObject import (
_GameObject_Components, _GameObject_GetComponent
)
from ..enums import ClassIDType

m_Components = property(_GameObject_Components)
m_Animator = property(
lambda self: _GameObject_GetComponent(self, ClassIDType.Animator)
)
m_Animation = property(
lambda self: _GameObject_GetComponent(self, ClassIDType.Animation)
)
m_Transform = property(
lambda self: _GameObject_GetComponent(self, ClassIDType.Transform)
)
m_MeshRenderer = property(
lambda self: _GameObject_GetComponent(self, ClassIDType.MeshRenderer)
)
m_SkinnedMeshRenderer = property(
lambda self: _GameObject_GetComponent(self, ClassIDType.SkinnedMeshRenderer)
)
m_MeshFilter = property(
lambda self: _GameObject_GetComponent(self, ClassIDType.MeshFilter)
)


@unitypy_define
class NamedObject(EditorExtension, ABC):
Expand Down Expand Up @@ -4054,6 +4084,11 @@ class AudioClip(SampleClip):
m_Type: Optional[int] = None
m_UseHardware: Optional[bool] = None

if TYPE_CHECKING:
from .legacy_patch.AudioClip import _AudioClip_extension, _AudioClip_samples
extension = property(_AudioClip_extension)
samples = property(_AudioClip_samples)


@unitypy_define
class Avatar(NamedObject):
Expand Down Expand Up @@ -4451,6 +4486,10 @@ class Mesh(NamedObject):
m_VertexData: Optional[VertexData] = None
m_Vertices: Optional[List[Vector3f]] = None

if TYPE_CHECKING:
from .legacy_patch.Mesh import _Mesh_export
export = _Mesh_export


@unitypy_define
class Motion(NamedObject, ABC):
Expand Down Expand Up @@ -4657,6 +4696,10 @@ class Shader(NamedObject):
platforms: Optional[List[int]] = None
stageCounts: Optional[List[int]] = None

if TYPE_CHECKING:
from .legacy_patch.Shader import _Shader_export
export = _Shader_export


@unitypy_define
class ShaderVariantCollection(NamedObject):
Expand Down Expand Up @@ -4691,6 +4734,10 @@ class Sprite(NamedObject):
m_ScriptableObjects: Optional[List[PPtr[MonoBehaviour]]] = None
m_SpriteAtlas: Optional[PPtr[SpriteAtlas]] = None

if TYPE_CHECKING:
from .legacy_patch.Sprite import _Sprite_image
image = property(_Sprite_image)


@unitypy_define
class SpriteAtlas(NamedObject):
Expand Down Expand Up @@ -4988,6 +5035,14 @@ class Texture2D(Texture):
m_StreamingMipmaps: Optional[bool] = None
m_StreamingMipmapsPriority: Optional[int] = None

if TYPE_CHECKING:
from .legacy_patch.Texture2D import (
_Texture2d_get_image, _Texture2D_get_image_data, _Texture2d_set_image
)
image = property(_Texture2d_get_image, _Texture2d_set_image)
set_image = _Texture2d_set_image
get_image_data = _Texture2D_get_image_data


@unitypy_define
class Cubemap(Texture2D):
Expand Down Expand Up @@ -5043,6 +5098,10 @@ class Texture2DArray(Texture):
m_StreamData: Optional[StreamingInfo] = None
m_UsageMode: Optional[int] = None

if TYPE_CHECKING:
from legacy_patch.Texture2DArray import _Texture2DArray_get_images
images = property(_Texture2DArray_get_images)


@unitypy_define
class Texture3D(Texture):
Expand Down
34 changes: 17 additions & 17 deletions UnityPy/tools/extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import os
from io import BytesIO
from pathlib import Path
from typing import Callable, Dict, List, Union
from typing import Callable, Dict, List, Optional, Tuple, Union

import UnityPy
from UnityPy.classes import (
Expand All @@ -19,6 +19,7 @@
Texture2D,
)
from UnityPy.enums.ClassIDType import ClassIDType
from UnityPy.files import SerializedFile


def export_obj(
Expand All @@ -27,8 +28,8 @@ def export_obj(
append_name: bool = False,
append_path_id: bool = False,
export_unknown_as_typetree: bool = False,
asset_filter: Callable[[Object], bool] = None,
) -> List[int]:
asset_filter: Optional[Callable[[Object], bool]] = None,
) -> List[Tuple[SerializedFile, int]]:
"""Exports the given object to the given filepath.

Args:
Expand Down Expand Up @@ -76,8 +77,8 @@ def extract_assets(
ignore_first_container_dirs: int = 0,
append_path_id: bool = False,
export_unknown_as_typetree: bool = False,
asset_filter: Callable[[Object], bool] = None,
) -> List[int]:
asset_filter: Optional[Callable[[Object], bool]] = None,
) -> List[Tuple[SerializedFile, int]]:
"""Extracts some or all assets from the given source.

Args:
Expand All @@ -90,7 +91,7 @@ def extract_assets(
asset_filter (func(object)->bool, optional): Determines whether to export an object. Defaults to all objects.

Returns:
List[int]: [description]
List[Tuple[SerializedFile, int]]: [description]
"""
# load source
env = UnityPy.load(src)
Expand Down Expand Up @@ -153,15 +154,15 @@ def defaulted_export_index(type: ClassIDType):
###############################################################################


def exportTextAsset(obj: TextAsset, fp: str, extension: str = ".txt") -> List[int]:
def exportTextAsset(obj: TextAsset, fp: str, extension: str = ".txt") -> List[Tuple[SerializedFile, int]]:
if not extension:
extension = ".txt"
with open(f"{fp}{extension}", "wb") as f:
f.write(obj.m_Script.encode("utf-8", "surrogateescape"))
return [(obj.assets_file, obj.object_reader.path_id)]


def exportFont(obj: Font, fp: str, extension: str = "") -> List[int]:
def exportFont(obj: Font, fp: str, extension: str = "") -> List[Tuple[SerializedFile, int]]:
# TODO - export glyphs
if obj.m_FontData:
extension = ".ttf"
Expand All @@ -172,15 +173,15 @@ def exportFont(obj: Font, fp: str, extension: str = "") -> List[int]:
return [(obj.assets_file, obj.object_reader.path_id)]


def exportMesh(obj: Mesh, fp: str, extension=".obj") -> List[int]:
def exportMesh(obj: Mesh, fp: str, extension=".obj") -> List[Tuple[SerializedFile, int]]:
if not extension:
extension = ".obj"
with open(f"{fp}{extension}", "wt", encoding="utf8", newline="") as f:
f.write(obj.export())
return [(obj.assets_file, obj.object_reader.path_id)]


def exportShader(obj: Shader, fp: str, extension=".txt") -> List[int]:
def exportShader(obj: Shader, fp: str, extension=".txt") -> List[Tuple[SerializedFile, int]]:
if not extension:
extension = ".txt"
with open(f"{fp}{extension}", "wt", encoding="utf8", newline="") as f:
Expand All @@ -190,7 +191,7 @@ def exportShader(obj: Shader, fp: str, extension=".txt") -> List[int]:

def exportMonoBehaviour(
obj: Union[MonoBehaviour, Object], fp: str, extension: str = ""
) -> List[int]:
) -> List[Tuple[SerializedFile, int]]:
export = None

if obj.object_reader.serialized_type.node:
Expand Down Expand Up @@ -224,7 +225,7 @@ def exportMonoBehaviour(
return [(obj.assets_file, obj.object_reader.path_id)]


def exportAudioClip(obj: AudioClip, fp: str, extension: str = "") -> List[int]:
def exportAudioClip(obj: AudioClip, fp: str, extension: str = "") -> List[Tuple[SerializedFile, int]]:
samples = obj.samples
if len(samples) == 0:
pass
Expand All @@ -239,7 +240,7 @@ def exportAudioClip(obj: AudioClip, fp: str, extension: str = "") -> List[int]:
return [(obj.assets_file, obj.object_reader.path_id)]


def exportSprite(obj: Sprite, fp: str, extension: str = ".png") -> List[int]:
def exportSprite(obj: Sprite, fp: str, extension: str = ".png") -> List[Tuple[SerializedFile, int]]:
if not extension:
extension = ".png"
obj.image.save(f"{fp}{extension}")
Expand All @@ -254,16 +255,15 @@ def exportSprite(obj: Sprite, fp: str, extension: str = ".png") -> List[int]:
return exported


def exportTexture2D(obj: Texture2D, fp: str, extension: str = ".png") -> List[int]:
def exportTexture2D(obj: Texture2D, fp: str, extension: str = ".png") -> List[Tuple[SerializedFile, int]]:
if not extension:
extension = ".png"
if obj.m_Width:
# textures can be empty
obj.image.save(f"{fp}{extension}")
return [(obj.assets_file, obj.path_id)]


def exportGameObject(obj: GameObject, fp: str, extension: str = "") -> List[int]:
def exportGameObject(obj: GameObject, fp: str, extension: str = "") -> List[Tuple[SerializedFile, int]]:
exported = [(obj.assets_file, obj.path_id)]
refs = crawl_obj(obj)
if refs:
Expand Down Expand Up @@ -299,7 +299,7 @@ def exportGameObject(obj: GameObject, fp: str, extension: str = "") -> List[int]
MONOBEHAVIOUR_TYPETREES: Dict["Assembly-Name.dll", Dict["Class-Name", List[Dict]]] = {}


def crawl_obj(obj: Object, ret: dict = None) -> Dict[int, Union[Object, PPtr]]:
def crawl_obj(obj: Object, ret: Optional[dict] = None) -> Dict[int, Union[Object, PPtr]]:
"""Crawls through the data struture of the object and returns a list of all the components."""
if not ret:
ret = {}
Expand Down