From 3b4b3014a03ce97d01d0a2526ca49bf1f0982231 Mon Sep 17 00:00:00 2001 From: chinosk <2248589280@qq.com> Date: Sat, 24 Feb 2024 23:23:34 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E6=94=AF=E6=8C=81=20Sprite=20Texture=20?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hook.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/src/hook.cpp b/src/hook.cpp index 6eda6c19..121b5948 100644 --- a/src/hook.cpp +++ b/src/hook.cpp @@ -1409,10 +1409,96 @@ namespace LocalizeAssets(result, name); } - + return result; } + bool (*Object_IsNativeObjectAlive)(void*); + + std::unordered_map loadedT2D{}; + void* getLocalT2D(const std::filesystem::path& path) { + if (g_asset_load_log) { + wprintf(L"getLocalTexture2D: %ls\n", path.c_str()); + } + + if (std::filesystem::exists(path)) { + if (auto it = loadedT2D.find(path.c_str()); it != loadedT2D.end()) { + if (Object_IsNativeObjectAlive(it->second)) { + return it->second; + } + else { + loadedT2D.erase(path.c_str()); + } + } + + static auto Texture2D_klass = il2cpp_symbols::get_class("UnityEngine.CoreModule.dll", "UnityEngine", "Texture2D"); + static auto Texture2D_ctor = reinterpret_cast( + il2cpp_symbols::get_method_pointer("UnityEngine.CoreModule.dll", "UnityEngine", "Texture2D", ".ctor", 2)); + static auto loadImage = reinterpret_cast( + il2cpp_resolve_icall("UnityEngine.ImageConversion::LoadImage(UnityEngine.Texture2D,System.Byte[],System.Boolean)") + ); + static auto ReadAllBytes = reinterpret_cast( + il2cpp_symbols::get_method_pointer("mscorlib.dll", "System.IO", "File", "ReadAllBytes", 1) + ); + + auto fileBytes = ReadAllBytes(il2cpp_symbols::NewWStr(path.c_str())); + auto ret = il2cpp_object_new(Texture2D_klass); + Texture2D_ctor(ret, 2, 2); + if (loadImage(ret, fileBytes, false)) { + loadedT2D.emplace(path.c_str(), ret); + return ret; + } + } + return NULL; + } + + void* Sprite_get_texture_orig = nullptr; + void* Sprite_get_texture_hook(void* _this) + { + static auto get_ObjectName = reinterpret_cast( + il2cpp_resolve_icall("UnityEngine.Object::GetName(UnityEngine.Object)")); + + auto texture2D = reinterpret_cast(Sprite_get_texture_orig)(_this); + if (g_replace_assets) { + auto object_name = get_ObjectName(texture2D); + static std::filesystem::path baseSearchPath = "localized_data/res"; + + if (object_name) { + const std::wstring objName(object_name->start_char); + + const std::wstring loadName = (baseSearchPath / objName).c_str(); + const auto& localT2D = getLocalT2D(loadName + L".png"); + if (localT2D) { + reinterpret_cast( + il2cpp_symbols::get_method_pointer("UnityEngine.CoreModule.dll", "UnityEngine", "Object", "set_hideFlags", 1) + )(localT2D, 32); + return localT2D; + } + + /* // 下方也可在 Assetbundle 中加载 + const auto& bundleHandle = GetBundleHandleByAssetName(loadName + L".png"); + if (bundleHandle) + { + const auto extraAssetBundle = il2cpp_gchandle_get_target(bundleHandle); + const auto cls = il2cpp_symbols::get_class_from_instance(texture2D); + auto ret = reinterpret_cast(AssetBundle_LoadAsset_orig)(extraAssetBundle, + il2cpp_string_new(loadName), il2cpp_type_get_object(il2cpp_class_get_type(cls))); + + if (ret) + { + reinterpret_cast( + il2cpp_symbols::get_method_pointer("UnityEngine.CoreModule.dll", "UnityEngine", "Object", "set_hideFlags", 1) + )(ret, 32); + } + return ret; + }*/ + + } + } + return texture2D; + } + + void* AssetBundleRequest_get_allAssets_orig; void* AssetBundleRequest_get_allAssets_hook(void* _this) { void* ret = reinterpret_cast(AssetBundleRequest_get_allAssets_orig)(_this); @@ -1451,8 +1537,6 @@ namespace uint32_t ReplaceFontHandle; - bool (*Object_IsNativeObjectAlive)(void*); - void* getReplaceFont() { void* replaceFont{}; const auto& bundleHandle = GetBundleHandleByAssetName(std::get(g_replace_font).FontPath); @@ -4352,6 +4436,7 @@ namespace il2cpp_resolve_icall("UnityEngine.AssetBundleRequest::get_allAssets()"); const auto AssetBundleRequest_GetResult_addr = il2cpp_resolve_icall("UnityEngine.AssetBundleRequest::GetResult()"); + auto Sprite_get_texture_addr = il2cpp_resolve_icall("UnityEngine.Sprite::get_texture(UnityEngine.Sprite)"); auto AssetLoader_LoadAssetHandle_addr = il2cpp_symbols::get_method_pointer( @@ -5104,6 +5189,7 @@ namespace ADD_HOOK(AssetBundle_LoadAssetAsync, "AssetBundle.LoadAsset at %p\n"); ADD_HOOK(AssetBundleRequest_get_allAssets, "AssetBundleRequest_get_allAssets at %p\n"); ADD_HOOK(AssetBundleRequest_GetResult, "AssetBundleRequest_GetResult at %p\n"); + ADD_HOOK(Sprite_get_texture, "Sprite_get_texture at %p\n"); } if (g_max_fps > -1) From 170b3b37b2b0f8b9330ddf0dfa9ec06026a1da19 Mon Sep 17 00:00:00 2001 From: chinosk <2248589280@qq.com> Date: Sat, 24 Feb 2024 23:26:35 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E8=B7=AF=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hook.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hook.cpp b/src/hook.cpp index 121b5948..199da512 100644 --- a/src/hook.cpp +++ b/src/hook.cpp @@ -1461,7 +1461,7 @@ namespace auto texture2D = reinterpret_cast(Sprite_get_texture_orig)(_this); if (g_replace_assets) { auto object_name = get_ObjectName(texture2D); - static std::filesystem::path baseSearchPath = "localized_data/res"; + static std::filesystem::path baseSearchPath = "localized_data/res/texture2d"; if (object_name) { const std::wstring objName(object_name->start_char); From 680957505551414c1213c82e3a1f0c03f637d14e Mon Sep 17 00:00:00 2001 From: chinosk <2248589280@qq.com> Date: Sun, 25 Feb 2024 00:28:43 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E6=94=AF=E6=8C=81=20dump=20sprite=20textur?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/config.json | 1 + resources/config.schema.json | 5 ++ resources/config_en.schema.json | 5 ++ resources/config_ja.schema.json | 5 ++ resources/config_zh_tw.schema.json | 5 ++ src/hook.cpp | 100 +++++++++++++++++++++++++++++ src/il2cpp/il2cpp_symbols.hpp | 39 +++++++++++ src/main.cpp | 5 ++ src/stdinclude.hpp | 1 + 9 files changed, 166 insertions(+) diff --git a/resources/config.json b/resources/config.json index 8ddaedd6..87e05966 100644 --- a/resources/config.json +++ b/resources/config.json @@ -24,6 +24,7 @@ "customFontStyle": 0, "customFontLinespacing": 0.6, "replaceAssets": true, + "dumpSpriteTexture": false, "assetLoadLog": false, "live": { "free_camera": false, diff --git a/resources/config.schema.json b/resources/config.schema.json index 2f7c0b10..5026a0f6 100644 --- a/resources/config.schema.json +++ b/resources/config.schema.json @@ -116,6 +116,11 @@ "description": "是否开启图片等资源替换", "type": "boolean" }, + "dumpSpriteTexture": { + "description": "Dump Sprite 图像资源", + "type": "boolean", + "default": false + }, "assetLoadLog": { "description": "是否在debug输出游戏资源调用情况", "type": "boolean" diff --git a/resources/config_en.schema.json b/resources/config_en.schema.json index 0769e48e..f33e8ec3 100644 --- a/resources/config_en.schema.json +++ b/resources/config_en.schema.json @@ -116,6 +116,11 @@ "description": "Replacing the game picture/texture with resource in extraAssetBundlePath if exist", "type": "boolean" }, + "dumpSpriteTexture": { + "description": "Dump Sprite Texture", + "type": "boolean", + "default": false + }, "assetLoadLog": { "description": "Print the asset bundle path of game resource that the game is using", "type": "boolean" diff --git a/resources/config_ja.schema.json b/resources/config_ja.schema.json index eaf95322..91fff3f8 100644 --- a/resources/config_ja.schema.json +++ b/resources/config_ja.schema.json @@ -116,6 +116,11 @@ "description": "画像やその他のリソースの置換を有効化します。", "type": "boolean" }, + "dumpSpriteTexture": { + "description": "Dump Sprite Texture", + "type": "boolean", + "default": false + }, "assetLoadLog": { "description": "デバッグ時にゲームリソースの呼び出し状況を出力します。", "type": "boolean" diff --git a/resources/config_zh_tw.schema.json b/resources/config_zh_tw.schema.json index d24b2147..9bc095ff 100644 --- a/resources/config_zh_tw.schema.json +++ b/resources/config_zh_tw.schema.json @@ -116,6 +116,11 @@ "description": "是否開啟圖片等素材替換", "type": "boolean" }, + "dumpSpriteTexture": { + "description": "Dump Sprite 素材", + "type": "boolean", + "default": false + }, "assetLoadLog": { "description": "是否在debug輸出遊戲素材調用情況", "type": "boolean" diff --git a/src/hook.cpp b/src/hook.cpp index 199da512..b359fdef 100644 --- a/src/hook.cpp +++ b/src/hook.cpp @@ -1413,8 +1413,104 @@ namespace return result; } + void replaceAll(std::string& str, const std::string& from, const std::string& to) + { + if (from.empty()) + return; + size_t start_pos = 0; + while ((start_pos = str.find(from, start_pos)) != std::string::npos) + { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' + } + } + bool (*Object_IsNativeObjectAlive)(void*); + void DumpTexture2D(Il2CppObject* texture, string type) + { + static auto get_ObjectName = reinterpret_cast( + il2cpp_resolve_icall("UnityEngine.Object::GetName(UnityEngine.Object)")); + static auto T2D_get_width = reinterpret_cast(il2cpp_class_get_method_from_name(texture->klass, "get_width", 0)->methodPointer); + static auto T2D_get_height = reinterpret_cast(il2cpp_class_get_method_from_name(texture->klass, "get_height", 0)->methodPointer); + static auto RenderTexture_GetTemporary = reinterpret_cast(il2cpp_symbols::get_method_pointer( + "UnityEngine.CoreModule.dll", "UnityEngine", "RenderTexture", "GetTemporary", 4)); + static auto Graphics_Blit = reinterpret_cast(il2cpp_symbols::get_method_pointer( + "UnityEngine.CoreModule.dll", "UnityEngine", "Graphics", "Blit", 2)); + static auto RenderTexture_get_active = reinterpret_cast(il2cpp_symbols::get_method_pointer( + "UnityEngine.CoreModule.dll", "UnityEngine", "RenderTexture", "get_active", -1)); + static auto RenderTexture_set_active = reinterpret_cast(il2cpp_symbols::get_method_pointer( + "UnityEngine.CoreModule.dll", "UnityEngine", "RenderTexture", "set_active", 1)); + static auto Texture2D_klass = il2cpp_symbols::get_class("UnityEngine.CoreModule.dll", "UnityEngine", "Texture2D"); + static auto Texture2D_ctor = reinterpret_cast( + il2cpp_symbols::get_method_pointer("UnityEngine.CoreModule.dll", "UnityEngine", "Texture2D", ".ctor", 2)); + static auto Texture2D_ReadPixels = reinterpret_cast( + il2cpp_symbols::get_method_pointer("UnityEngine.CoreModule.dll", "UnityEngine", "Texture2D", "ReadPixels", 3)); + static auto Texture2D_Apply = reinterpret_cast( + il2cpp_symbols::get_method_pointer("UnityEngine.CoreModule.dll", "UnityEngine", "Texture2D", "Apply", 0)); + static auto RenderTexture_ReleaseTemporary = reinterpret_cast(il2cpp_symbols::get_method_pointer( + "UnityEngine.CoreModule.dll", "UnityEngine", "RenderTexture", "ReleaseTemporary", 1)); + static auto File_WriteAllBytes = reinterpret_cast*)>( + il2cpp_symbols::get_method_pointer("mscorlib.dll", "System.IO", "File", "WriteAllBytes", 2)); + + + std::string textureName = utility::conversions::to_utf8string(get_ObjectName(texture)->start_char); + replaceAll(textureName, "|", "_"); + const auto saveName = "localized_data/TextureDump/" + type + "/" + textureName + ".png"; + if (std::filesystem::exists(saveName)) { + return; + } + + const auto width = T2D_get_width(texture); + const auto height = T2D_get_height(texture); + auto renderTexture = RenderTexture_GetTemporary(width, height, 0, 0); + Graphics_Blit(texture, renderTexture); + + auto previous = RenderTexture_get_active(); + RenderTexture_set_active(renderTexture); + + auto readableTexture = il2cpp_object_new(Texture2D_klass); + Texture2D_ctor(readableTexture, width, height); + + + Texture2D_ReadPixels(readableTexture, Rect_t{ 0, 0, static_cast(width), static_cast(height) }, 0, 0); + Texture2D_Apply(readableTexture); + + RenderTexture_set_active(previous); + + RenderTexture_ReleaseTemporary(renderTexture); + + auto method = il2cpp_symbols::get_method("UnityEngine.ImageConversionModule.dll", "UnityEngine", "ImageConversion", "EncodeToPNG", 1); + + void** params = new void* [1]; + params[0] = readableTexture; + + Il2CppObject* exception; + + auto pngData = reinterpret_cast*>(il2cpp_runtime_invoke(method, nullptr, params, &exception)); + + if (exception) + { + printf("dump error: %s\n", saveName.c_str()); + // il2cpp_raise_exception(exception); + return; + } + + + if (!filesystem::exists("localized_data/TextureDump")) + { + filesystem::create_directories("localized_data/TextureDump"); + } + + if (!filesystem::exists("localized_data/TextureDump/" + type)) + { + filesystem::create_directory("localized_data/TextureDump/" + type); + } + + printf("dumpFile: %s\n", saveName.c_str()); + File_WriteAllBytes(il2cpp_string_new(saveName.c_str()), pngData); + } + std::unordered_map loadedT2D{}; void* getLocalT2D(const std::filesystem::path& path) { if (g_asset_load_log) { @@ -1459,6 +1555,10 @@ namespace il2cpp_resolve_icall("UnityEngine.Object::GetName(UnityEngine.Object)")); auto texture2D = reinterpret_cast(Sprite_get_texture_orig)(_this); + if (g_dump_sprite_tex) { + DumpTexture2D((Il2CppObject*)texture2D, "sprite_tex"); + } + if (g_replace_assets) { auto object_name = get_ObjectName(texture2D); static std::filesystem::path baseSearchPath = "localized_data/res/texture2d"; diff --git a/src/il2cpp/il2cpp_symbols.hpp b/src/il2cpp/il2cpp_symbols.hpp index 4d3cb151..f3a7ac1c 100644 --- a/src/il2cpp/il2cpp_symbols.hpp +++ b/src/il2cpp/il2cpp_symbols.hpp @@ -244,6 +244,36 @@ typedef struct Il2CppArraySize void* vector[0]; } Il2CppArraySize; +typedef struct Il2CppException +{ + Il2CppObject object; + Il2CppString* className; + Il2CppString* message; + Il2CppObject* _data; + Il2CppException* inner_ex; + Il2CppString* _helpURL; + Il2CppArraySize* trace_ips; + Il2CppString* stack_trace; + Il2CppString* remote_stack_trace; + int remote_stack_index; + Il2CppObject* _dynamicMethods; + int32_t hresult; + Il2CppString* source; + Il2CppObject* safeSerializationManager; + Il2CppArraySize* captured_traces; + Il2CppArraySize* native_trace_ips; +} Il2CppException; + +template +struct Il2CppArraySize_t +{ + Il2CppObject obj; + void* bounds; + uintptr_t max_length; + alignas(8) + T vector[0]; +}; + struct Il2CppClassHead { const void* image; @@ -258,6 +288,15 @@ struct Il2CppReflectionType const Il2CppType* type; }; +struct Rect_t +{ +public: + float x; + float y; + float width; + float height; +}; + static const size_t kIl2CppSizeOfArray = (offsetof(Il2CppArraySize, vector)); // function types diff --git a/src/main.cpp b/src/main.cpp index eecad667..c1390525 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -90,6 +90,7 @@ std::wstring g_self_server_url; bool g_enable_cutin_first_person = false; bool g_cutin_first_person = false; +bool g_dump_sprite_tex = false; std::string g_text_data_dict_path; std::string g_character_system_text_dict_path; @@ -747,6 +748,10 @@ namespace raceInfoTabAttachToGame = document["raceInfoTab"]["raceInfoTabAttachToGame"].GetBool(); } + if (document.HasMember("dumpSpriteTexture")) { + g_dump_sprite_tex = document["dumpSpriteTexture"].GetBool(); + } + // Looks like not working for now // g_aspect_ratio = document["customAspectRatio"].GetFloat(); diff --git a/src/stdinclude.hpp b/src/stdinclude.hpp index 68639587..2efbe5fd 100644 --- a/src/stdinclude.hpp +++ b/src/stdinclude.hpp @@ -198,3 +198,4 @@ extern bool g_enable_custom_PersistentDataPath; extern std::string g_custom_PersistentDataPath; extern bool g_upload_gacha_history; extern std::wstring g_upload_gacha_history_endpoint; +extern bool g_dump_sprite_tex; From 7c6c67d62aa99f395ae7384d5e8575aa168fffe3 Mon Sep 17 00:00:00 2001 From: chinosk <2248589280@qq.com> Date: Sun, 25 Feb 2024 01:28:37 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E6=94=AF=E6=8C=81=20bundle=20=E4=B8=AD=20T?= =?UTF-8?q?exture=20=E6=9C=AC=E5=9C=B0=E6=96=87=E4=BB=B6=E6=9B=BF=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/config.json | 1 + resources/config.schema.json | 5 ++ resources/config_en.schema.json | 5 ++ resources/config_ja.schema.json | 5 ++ resources/config_zh_tw.schema.json | 5 ++ src/hook.cpp | 98 ++++++++++++++++-------------- src/main.cpp | 4 ++ src/stdinclude.hpp | 1 + 8 files changed, 77 insertions(+), 47 deletions(-) diff --git a/resources/config.json b/resources/config.json index 87e05966..315274e9 100644 --- a/resources/config.json +++ b/resources/config.json @@ -25,6 +25,7 @@ "customFontLinespacing": 0.6, "replaceAssets": true, "dumpSpriteTexture": false, + "dumpRuntimeTexture": false, "assetLoadLog": false, "live": { "free_camera": false, diff --git a/resources/config.schema.json b/resources/config.schema.json index 5026a0f6..7f1e4161 100644 --- a/resources/config.schema.json +++ b/resources/config.schema.json @@ -121,6 +121,11 @@ "type": "boolean", "default": false }, + "dumpRuntimeTexture": { + "description": "Dump Runtime 图像资源", + "type": "boolean", + "default": false + }, "assetLoadLog": { "description": "是否在debug输出游戏资源调用情况", "type": "boolean" diff --git a/resources/config_en.schema.json b/resources/config_en.schema.json index f33e8ec3..456a184e 100644 --- a/resources/config_en.schema.json +++ b/resources/config_en.schema.json @@ -121,6 +121,11 @@ "type": "boolean", "default": false }, + "dumpRuntimeTexture": { + "description": "Dump Runtime Texture", + "type": "boolean", + "default": false + }, "assetLoadLog": { "description": "Print the asset bundle path of game resource that the game is using", "type": "boolean" diff --git a/resources/config_ja.schema.json b/resources/config_ja.schema.json index 91fff3f8..b5254c51 100644 --- a/resources/config_ja.schema.json +++ b/resources/config_ja.schema.json @@ -121,6 +121,11 @@ "type": "boolean", "default": false }, + "dumpRuntimeTexture": { + "description": "Dump Runtime Texture", + "type": "boolean", + "default": false + }, "assetLoadLog": { "description": "デバッグ時にゲームリソースの呼び出し状況を出力します。", "type": "boolean" diff --git a/resources/config_zh_tw.schema.json b/resources/config_zh_tw.schema.json index 9bc095ff..34762dc2 100644 --- a/resources/config_zh_tw.schema.json +++ b/resources/config_zh_tw.schema.json @@ -121,6 +121,11 @@ "type": "boolean", "default": false }, + "dumpRuntimeTexture": { + "description": "Dump Runtime 素材", + "type": "boolean", + "default": false + }, "assetLoadLog": { "description": "是否在debug輸出遊戲素材調用情況", "type": "boolean" diff --git a/src/hook.cpp b/src/hook.cpp index b359fdef..ca30ead6 100644 --- a/src/hook.cpp +++ b/src/hook.cpp @@ -22,6 +22,18 @@ void _set_u_stat(bool s) { } } +// copy-pasted from https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string +void replaceAll(std::string& str, const std::string& from, const std::string& to) { + if (from.empty()) + return; + size_t start_pos = 0; + while ((start_pos = str.find(from, start_pos)) != std::string::npos) + { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' + } +} + void LoadExtraAssetBundle(); namespace @@ -1115,6 +1127,7 @@ namespace FieldInfo* RubyDataClass_CharX; FieldInfo* RubyDataClass_CharY; FieldInfo* RubyDataClass_RubyText; + void* Texture2DClass; uint32_t GetBundleHandleByAssetName(wstring assetName) { for (const auto& i : CustomAssetBundleAssetPaths) { @@ -1277,7 +1290,10 @@ namespace }); } - void LocalizeAssets(void* result, Il2CppString* name) { + void* getLocalT2D(const std::filesystem::path& path); + void DumpTexture2D(Il2CppObject* texture, const std::filesystem::path& savePath); + + void LocalizeAssets(void*& result, Il2CppString* name) { const auto cls = il2cpp_symbols::get_class_from_instance(result); if (cls == StoryTimelineDataClass) { @@ -1306,6 +1322,23 @@ namespace else if (cls == TextRubyDataClass) { LocalizeStoryTextRubyData(result); } + else if (cls == Texture2DClass) { + static const std::filesystem::path textureBasePath = "localized_data/res/texture2d/fromBundle"; + const std::filesystem::path texturePath = name->start_char; + const auto localPath = textureBasePath / name->start_char; + if (g_dump_bundle_tex) { + DumpTexture2D((Il2CppObject*)result, texturePath.parent_path()); + } + + if (g_replace_assets) { + if (std::filesystem::exists(localPath)) { + auto replaceT2D = getLocalT2D(localPath); + if (replaceT2D) { + result = replaceT2D; + } + } + } + } } void* AssetBundle_LoadAsset_orig; @@ -1413,22 +1446,10 @@ namespace return result; } - void replaceAll(std::string& str, const std::string& from, const std::string& to) - { - if (from.empty()) - return; - size_t start_pos = 0; - while ((start_pos = str.find(from, start_pos)) != std::string::npos) - { - str.replace(start_pos, from.length(), to); - start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' - } - } - bool (*Object_IsNativeObjectAlive)(void*); - void DumpTexture2D(Il2CppObject* texture, string type) - { + // steps from github @Kimjio + void DumpTexture2D(Il2CppObject* texture, const std::filesystem::path& savePath) { static auto get_ObjectName = reinterpret_cast( il2cpp_resolve_icall("UnityEngine.Object::GetName(UnityEngine.Object)")); static auto T2D_get_width = reinterpret_cast(il2cpp_class_get_method_from_name(texture->klass, "get_width", 0)->methodPointer); @@ -1441,7 +1462,6 @@ namespace "UnityEngine.CoreModule.dll", "UnityEngine", "RenderTexture", "get_active", -1)); static auto RenderTexture_set_active = reinterpret_cast(il2cpp_symbols::get_method_pointer( "UnityEngine.CoreModule.dll", "UnityEngine", "RenderTexture", "set_active", 1)); - static auto Texture2D_klass = il2cpp_symbols::get_class("UnityEngine.CoreModule.dll", "UnityEngine", "Texture2D"); static auto Texture2D_ctor = reinterpret_cast( il2cpp_symbols::get_method_pointer("UnityEngine.CoreModule.dll", "UnityEngine", "Texture2D", ".ctor", 2)); static auto Texture2D_ReadPixels = reinterpret_cast( @@ -1452,11 +1472,14 @@ namespace "UnityEngine.CoreModule.dll", "UnityEngine", "RenderTexture", "ReleaseTemporary", 1)); static auto File_WriteAllBytes = reinterpret_cast*)>( il2cpp_symbols::get_method_pointer("mscorlib.dll", "System.IO", "File", "WriteAllBytes", 2)); + static auto ImageConversion_EncodeToPNG_mtd = il2cpp_symbols::get_method( + "UnityEngine.ImageConversionModule.dll", "UnityEngine", "ImageConversion", "EncodeToPNG", 1); + const std::filesystem::path baseDumpPath = "localized_data/TextureDump"; std::string textureName = utility::conversions::to_utf8string(get_ObjectName(texture)->start_char); replaceAll(textureName, "|", "_"); - const auto saveName = "localized_data/TextureDump/" + type + "/" + textureName + ".png"; + const auto saveName = baseDumpPath / savePath / (textureName + ".png"); if (std::filesystem::exists(saveName)) { return; } @@ -1465,50 +1488,32 @@ namespace const auto height = T2D_get_height(texture); auto renderTexture = RenderTexture_GetTemporary(width, height, 0, 0); Graphics_Blit(texture, renderTexture); - auto previous = RenderTexture_get_active(); RenderTexture_set_active(renderTexture); - - auto readableTexture = il2cpp_object_new(Texture2D_klass); + auto readableTexture = il2cpp_object_new(Texture2DClass); Texture2D_ctor(readableTexture, width, height); - - Texture2D_ReadPixels(readableTexture, Rect_t{ 0, 0, static_cast(width), static_cast(height) }, 0, 0); Texture2D_Apply(readableTexture); - RenderTexture_set_active(previous); - RenderTexture_ReleaseTemporary(renderTexture); - auto method = il2cpp_symbols::get_method("UnityEngine.ImageConversionModule.dll", "UnityEngine", "ImageConversion", "EncodeToPNG", 1); - void** params = new void* [1]; params[0] = readableTexture; - Il2CppObject* exception; + auto pngData = reinterpret_cast*>(il2cpp_runtime_invoke(ImageConversion_EncodeToPNG_mtd, nullptr, params, &exception)); + delete[] params; - auto pngData = reinterpret_cast*>(il2cpp_runtime_invoke(method, nullptr, params, &exception)); - - if (exception) - { - printf("dump error: %s\n", saveName.c_str()); - // il2cpp_raise_exception(exception); + if (exception) { + printf("dump error: %ls\n", saveName.c_str()); return; } - - if (!filesystem::exists("localized_data/TextureDump")) - { - filesystem::create_directories("localized_data/TextureDump"); - } - - if (!filesystem::exists("localized_data/TextureDump/" + type)) - { - filesystem::create_directory("localized_data/TextureDump/" + type); + if (!filesystem::exists(baseDumpPath / savePath)) { + filesystem::create_directories(baseDumpPath / savePath); } - printf("dumpFile: %s\n", saveName.c_str()); - File_WriteAllBytes(il2cpp_string_new(saveName.c_str()), pngData); + printf("dumpFile: %ls\n", saveName.c_str()); + File_WriteAllBytes(il2cpp_symbols::NewWStr(saveName.c_str()), pngData); } std::unordered_map loadedT2D{}; @@ -1527,7 +1532,6 @@ namespace } } - static auto Texture2D_klass = il2cpp_symbols::get_class("UnityEngine.CoreModule.dll", "UnityEngine", "Texture2D"); static auto Texture2D_ctor = reinterpret_cast( il2cpp_symbols::get_method_pointer("UnityEngine.CoreModule.dll", "UnityEngine", "Texture2D", ".ctor", 2)); static auto loadImage = reinterpret_cast( @@ -1538,7 +1542,7 @@ namespace ); auto fileBytes = ReadAllBytes(il2cpp_symbols::NewWStr(path.c_str())); - auto ret = il2cpp_object_new(Texture2D_klass); + auto ret = il2cpp_object_new(Texture2DClass); Texture2D_ctor(ret, 2, 2); if (loadImage(ret, fileBytes, false)) { loadedT2D.emplace(path.c_str(), ret); @@ -4494,7 +4498,7 @@ namespace "TMP_Text", "set_font", 1 )); - + Texture2DClass = il2cpp_symbols::get_class("UnityEngine.CoreModule.dll", "UnityEngine", "Texture2D"); TextRubyDataClass = il2cpp_symbols::get_class("umamusume.dll", "", "TextRubyData"); TextRubyDataClass_DataArray = il2cpp_class_get_field_from_name(TextRubyDataClass, "DataArray"); diff --git a/src/main.cpp b/src/main.cpp index c1390525..436a47e8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -91,6 +91,7 @@ std::wstring g_self_server_url; bool g_enable_cutin_first_person = false; bool g_cutin_first_person = false; bool g_dump_sprite_tex = false; +bool g_dump_bundle_tex = false; std::string g_text_data_dict_path; std::string g_character_system_text_dict_path; @@ -751,6 +752,9 @@ namespace if (document.HasMember("dumpSpriteTexture")) { g_dump_sprite_tex = document["dumpSpriteTexture"].GetBool(); } + if (document.HasMember("dumpRuntimeTexture")) { + g_dump_bundle_tex = document["dumpRuntimeTexture"].GetBool(); + } // Looks like not working for now // g_aspect_ratio = document["customAspectRatio"].GetFloat(); diff --git a/src/stdinclude.hpp b/src/stdinclude.hpp index 2efbe5fd..733aac07 100644 --- a/src/stdinclude.hpp +++ b/src/stdinclude.hpp @@ -199,3 +199,4 @@ extern std::string g_custom_PersistentDataPath; extern bool g_upload_gacha_history; extern std::wstring g_upload_gacha_history_endpoint; extern bool g_dump_sprite_tex; +extern bool g_dump_bundle_tex;