diff --git a/UnityPy/classes/legacy_patch/AudioClip.pyi b/UnityPy/classes/legacy_patch/AudioClip.pyi new file mode 100644 index 00000000..6f8da3c1 --- /dev/null +++ b/UnityPy/classes/legacy_patch/AudioClip.pyi @@ -0,0 +1,31 @@ +from typing import Dict, List, Optional + +from UnityPy.classes.generated import SampleClip, StreamedResource + +class AudioClip(SampleClip): + m_Name: str + m_3D: Optional[bool] = None + m_Ambisonic: Optional[bool] = None + m_AudioData: Optional[List[int]] = None + m_BitsPerSample: Optional[int] = None + m_Channels: Optional[int] = None + m_CompressionFormat: Optional[int] = None + m_Format: Optional[int] = None + m_Frequency: Optional[int] = None + m_IsTrackerFormat: Optional[bool] = None + m_Legacy3D: Optional[bool] = None + m_Length: Optional[float] = None + m_LoadInBackground: Optional[bool] = None + m_LoadType: Optional[int] = None + m_PreloadAudioData: Optional[bool] = None + m_Resource: Optional[StreamedResource] = None + m_Stream: Optional[int] = None + m_SubsoundIndex: Optional[int] = None + m_Type: Optional[int] = None + m_UseHardware: Optional[bool] = None + + @property + def extension(self) -> str: ... + + @property + def samples(self) -> Dict[str, bytes]: ... diff --git a/UnityPy/classes/legacy_patch/GameObject.pyi b/UnityPy/classes/legacy_patch/GameObject.pyi new file mode 100644 index 00000000..1a414316 --- /dev/null +++ b/UnityPy/classes/legacy_patch/GameObject.pyi @@ -0,0 +1,26 @@ +from typing import List, Tuple, Union + +from UnityPy.classes import Component, PPtr +from UnityPy.classes.generated import ComponentPair, EditorExtension + +class GameObject(EditorExtension): + m_Component: Union[List[ComponentPair], List[Tuple[int, PPtr[Component]]]] + m_IsActive: Union[bool, int] + m_Layer: int + m_Name: str + m_Tag: int + + @property + def m_Components(self) -> List[PPtr[Component]]: ... + @property + def m_Animator(self) -> Union[PPtr[Component], None]: ... + @property + def m_Animation(self) -> Union[PPtr[Component], None]: ... + @property + def m_Transform(self) -> Union[PPtr[Component], None]: ... + @property + def m_SkinnedMeshRenderer(self) -> Union[PPtr[Component], None]: ... + @property + def m_MeshRenderer(self) -> Union[PPtr[Component], None]: ... + @property + def m_MeshFilter(self) -> Union[PPtr[Component], None]: ... diff --git a/UnityPy/classes/legacy_patch/Mesh.pyi b/UnityPy/classes/legacy_patch/Mesh.pyi new file mode 100644 index 00000000..9d047012 --- /dev/null +++ b/UnityPy/classes/legacy_patch/Mesh.pyi @@ -0,0 +1,50 @@ +from typing import List, Optional, Union + +from UnityPy.classes.generated import (AABB, BlendShapeData, BoneInfluence, + BoneWeights4, CompressedMesh, + MeshBlendShape, MeshBlendShapeVertex, + MinMaxAABB, NamedObject, StreamingInfo, + SubMesh, VariableBoneCountWeights, + VertexData) +from UnityPy.classes.math import (ColorRGBA, Matrix4x4f, Vector2f, Vector3f, + Vector4f) + +class Mesh(NamedObject): + m_BindPose: List[Matrix4x4f] + m_CompressedMesh: CompressedMesh + m_IndexBuffer: List[int] + m_LocalAABB: AABB + m_MeshCompression: int + m_MeshUsageFlags: int + m_Name: str + m_SubMeshes: List[SubMesh] + m_BakedConvexCollisionMesh: Optional[List[int]] = None + m_BakedTriangleCollisionMesh: Optional[List[int]] = None + m_BoneNameHashes: Optional[List[int]] = None + m_BonesAABB: Optional[List[MinMaxAABB]] = None + m_CollisionTriangles: Optional[List[int]] = None + m_CollisionVertexCount: Optional[int] = None + m_Colors: Optional[List[ColorRGBA]] = None + m_CookingOptions: Optional[int] = None + m_IndexFormat: Optional[int] = None + m_IsReadable: Optional[bool] = None + m_KeepIndices: Optional[bool] = None + m_KeepVertices: Optional[bool] = None + m_MeshMetrics_0_: Optional[float] = None + m_MeshMetrics_1_: Optional[float] = None + m_Normals: Optional[List[Vector3f]] = None + m_RootBoneNameHash: Optional[int] = None + m_ShapeVertices: Optional[List[MeshBlendShapeVertex]] = None + m_Shapes: Optional[Union[BlendShapeData, List[MeshBlendShape]]] = None + m_Skin: Optional[Union[List[BoneInfluence], List[BoneWeights4]]] = None + m_StreamCompression: Optional[int] = None + m_StreamData: Optional[StreamingInfo] = None + m_Tangents: Optional[List[Vector4f]] = None + m_UV: Optional[List[Vector2f]] = None + m_UV1: Optional[List[Vector2f]] = None + m_Use16BitIndices: Optional[int] = None + m_VariableBoneCountWeights: Optional[VariableBoneCountWeights] = None + m_VertexData: Optional[VertexData] = None + m_Vertices: Optional[List[Vector3f]] = None + + def export(self, format: str = "obj") -> str: ... diff --git a/UnityPy/classes/legacy_patch/Renderer.pyi b/UnityPy/classes/legacy_patch/Renderer.pyi new file mode 100644 index 00000000..a5e8c2c4 --- /dev/null +++ b/UnityPy/classes/legacy_patch/Renderer.pyi @@ -0,0 +1,8 @@ +from UnityPy.classes import PPtr +from UnityPy.classes.generated import Component +from UnityPy.classes.legacy_patch import GameObject + +class Renderer(Component): + m_GameObject: PPtr[GameObject] + + def export(self, export_dir: str) -> None: ... diff --git a/UnityPy/classes/legacy_patch/Shader.pyi b/UnityPy/classes/legacy_patch/Shader.pyi new file mode 100644 index 00000000..5b433964 --- /dev/null +++ b/UnityPy/classes/legacy_patch/Shader.pyi @@ -0,0 +1,25 @@ +from typing import List, Optional, Tuple, Union + +from UnityPy.classes import PPtr +from UnityPy.classes.generated import (GUID, NamedObject, SerializedShader, + Texture) + +class Shader(NamedObject): + m_Name: str + compressedBlob: Optional[List[int]] = None + compressedLengths: Optional[Union[List[int], List[List[int]]]] = None + decompressedLengths: Optional[Union[List[int], List[List[int]]]] = None + decompressedSize: Optional[int] = None + m_AssetGUID: Optional[GUID] = None + m_Dependencies: Optional[List[PPtr[Shader]]] = None + m_NonModifiableTextures: Optional[List[Tuple[str, PPtr[Texture]]]] = None + m_ParsedForm: Optional[SerializedShader] = None + m_PathName: Optional[str] = None + m_Script: Optional[str] = None + m_ShaderIsBaked: Optional[bool] = None + m_SubProgramBlob: Optional[List[int]] = None + offsets: Optional[Union[List[int], List[List[int]]]] = None + platforms: Optional[List[int]] = None + stageCounts: Optional[List[int]] = None + + def export(self) -> str: ... diff --git a/UnityPy/classes/legacy_patch/Sprite.pyi b/UnityPy/classes/legacy_patch/Sprite.pyi new file mode 100644 index 00000000..3b3b18c1 --- /dev/null +++ b/UnityPy/classes/legacy_patch/Sprite.pyi @@ -0,0 +1,29 @@ +from typing import List, Optional, Tuple + +from PIL.Image import Image + +from UnityPy.classes import PPtr +from UnityPy.classes.generated import (GUID, MonoBehaviour, NamedObject, Rectf, + SpriteAtlas, SpriteBone, + SpriteRenderData) +from UnityPy.classes.math import Vector2f, Vector4f + +class Sprite(NamedObject): + m_Extrude: int + m_Name: str + m_Offset: Vector2f + m_PixelsToUnits: float + m_RD: SpriteRenderData + m_Rect: Rectf + m_AtlasTags: Optional[List[str]] = None + m_Bones: Optional[List[SpriteBone]] = None + m_Border: Optional[Vector4f] = None + m_IsPolygon: Optional[bool] = None + m_PhysicsShape: Optional[List[List[Vector2f]]] = None + m_Pivot: Optional[Vector2f] = None + m_RenderDataKey: Optional[Tuple[GUID, int]] = None + m_ScriptableObjects: Optional[List[PPtr[MonoBehaviour]]] = None + m_SpriteAtlas: Optional[PPtr[SpriteAtlas]] = None + + @property + def image(self) -> Image: ... diff --git a/UnityPy/classes/legacy_patch/Texture2D.pyi b/UnityPy/classes/legacy_patch/Texture2D.pyi new file mode 100644 index 00000000..40f26fa2 --- /dev/null +++ b/UnityPy/classes/legacy_patch/Texture2D.pyi @@ -0,0 +1,45 @@ +from typing import BinaryIO, List, Optional, Union + +from PIL.Image import Image + +from UnityPy.classes.generated import GLTextureSettings, StreamingInfo, Texture + +class Texture2D(Texture): + image_data: bytes + m_CompleteImageSize: int + m_Height: int + m_ImageCount: int + m_IsReadable: bool + m_LightmapFormat: int + m_Name: str + m_TextureDimension: int + m_TextureFormat: int + m_TextureSettings: GLTextureSettings + m_Width: int + m_ColorSpace: Optional[int] = None + m_DownscaleFallback: Optional[bool] = None + m_ForcedFallbackFormat: Optional[int] = None + m_IgnoreMasterTextureLimit: Optional[bool] = None + m_IgnoreMipmapLimit: Optional[bool] = None + m_IsAlphaChannelOptional: Optional[bool] = None + m_IsPreProcessed: Optional[bool] = None + m_MipCount: Optional[int] = None + m_MipMap: Optional[bool] = None + m_MipmapLimitGroupName: Optional[str] = None + m_MipsStripped: Optional[int] = None + m_PlatformBlob: Optional[List[int]] = None + m_ReadAllowed: Optional[bool] = None + m_StreamData: Optional[StreamingInfo] = None + m_StreamingMipmaps: Optional[bool] = None + m_StreamingMipmapsPriority: Optional[int] = None + + @property + def image(self) -> Image: ... + def set_image( + self, + img: Union[Image, str, BinaryIO], + target_format: Optional[int] = None, + mipmap_count: int = 1, + ) -> None: ... + def get_image_data(self) -> bytes: ... + diff --git a/UnityPy/classes/legacy_patch/Texture2DArray.pyi b/UnityPy/classes/legacy_patch/Texture2DArray.pyi new file mode 100644 index 00000000..3f396ae7 --- /dev/null +++ b/UnityPy/classes/legacy_patch/Texture2DArray.pyi @@ -0,0 +1,29 @@ +from typing import List, Optional + +from PIL.Image import Image + +from UnityPy.classes.generated import GLTextureSettings, StreamingInfo, Texture + +class Texture2DArray(Texture): + image_data: bytes + m_ColorSpace: int + m_DataSize: int + m_Depth: int + m_Format: int + m_Height: int + m_IsReadable: bool + m_MipCount: int + m_Name: str + m_TextureSettings: GLTextureSettings + m_Width: int + m_DownscaleFallback: Optional[bool] = None + m_ForcedFallbackFormat: Optional[int] = None + m_IgnoreMipmapLimit: Optional[bool] = None + m_IsAlphaChannelOptional: Optional[bool] = None + m_MipmapLimitGroupName: Optional[str] = None + m_MipsStripped: Optional[int] = None + m_StreamData: Optional[StreamingInfo] = None + m_UsageMode: Optional[int] = None + + @property + def images(self) -> List[Image]: ... diff --git a/UnityPy/tools/extractor.py b/UnityPy/tools/extractor.py index cbe729a7..16a13f6c 100644 --- a/UnityPy/tools/extractor.py +++ b/UnityPy/tools/extractor.py @@ -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 ( @@ -19,6 +19,7 @@ Texture2D, ) from UnityPy.enums.ClassIDType import ClassIDType +from UnityPy.files import SerializedFile def export_obj( @@ -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: @@ -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: @@ -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) @@ -153,7 +154,7 @@ 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: @@ -161,7 +162,7 @@ def exportTextAsset(obj: TextAsset, fp: str, extension: str = ".txt") -> List[in 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" @@ -172,7 +173,7 @@ 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: @@ -180,7 +181,7 @@ def exportMesh(obj: Mesh, fp: str, extension=".obj") -> List[int]: 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: @@ -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: @@ -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 @@ -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}") @@ -254,7 +255,7 @@ 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: @@ -262,8 +263,7 @@ def exportTexture2D(obj: Texture2D, fp: str, extension: str = ".png") -> List[in 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: @@ -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 = {}