diff --git a/cheat-library/cheat-library.vcxproj b/cheat-library/cheat-library.vcxproj
index bf885e9..ab88e3d 100644
--- a/cheat-library/cheat-library.vcxproj
+++ b/cheat-library/cheat-library.vcxproj
@@ -15,6 +15,7 @@
+
false
@@ -116,6 +117,7 @@
+
false
diff --git a/cheat-library/cheat-library.vcxproj.filters b/cheat-library/cheat-library.vcxproj.filters
index fb22fb8..5f3f132 100644
--- a/cheat-library/cheat-library.vcxproj.filters
+++ b/cheat-library/cheat-library.vcxproj.filters
@@ -234,6 +234,9 @@
Header Files
+
+ Header Files
+
@@ -426,6 +429,9 @@
Source Files
+
+ Source Files
+
diff --git a/cheat-library/src/appdata/il2cpp-functions.h b/cheat-library/src/appdata/il2cpp-functions.h
index 93995be..a69ab18 100644
--- a/cheat-library/src/appdata/il2cpp-functions.h
+++ b/cheat-library/src/appdata/il2cpp-functions.h
@@ -178,6 +178,11 @@ DO_APP_FUNC(0x065508C0, void, Object_1_DestroyImmediate_1, (Object_1* obj, Metho
DO_APP_FUNC(0x06550C00, Object_1*, Object_1_Instantiate_2, (Object_1* original, MethodInfo* method));
DO_APP_FUNC(0x041B0BB0, Object*, Object_1_Instantiate_5, (Object* original, MethodInfo* method));
DO_APP_FUNC(0x041B0BB0, GameObject*, Object_1_Instantiate_11, (GameObject* original, MethodInfo* method));
+DO_APP_FUNC(0x06555870, int32_t, Transform_get_childCount, (Transform* __this, MethodInfo* method));
+DO_APP_FUNC(0x0652EBC0, GameObject*, Component_1_get_gameObject, (Component_1* __this, MethodInfo* method));
+DO_APP_FUNC(0x06551030, String*, Object_1_get_name, (Object_1* __this, MethodInfo* method));
+DO_APP_FUNC(0x0665DA90, Material__Array*, Renderer_GetMaterialArray, (Renderer* __this, MethodInfo* method));
+DO_APP_FUNC(0x0652FB40, void, Material_set_mainTexture, (Material* __this, Texture* value, MethodInfo* method));
// Music game event
diff --git a/cheat-library/src/appdata/il2cpp-types.h b/cheat-library/src/appdata/il2cpp-types.h
index 3060455..0239083 100644
--- a/cheat-library/src/appdata/il2cpp-types.h
+++ b/cheat-library/src/appdata/il2cpp-types.h
@@ -11414,6 +11414,12 @@ namespace app {
struct Object_1__Fields _;
};
+ struct Texture {
+ struct Texture__Class* klass;
+ MonitorData* monitor;
+ struct Texture__Fields fields;
+ };
+
struct Texture2D__Fields {
struct Texture__Fields _;
};
@@ -11424,9 +11430,6 @@ namespace app {
struct Texture2D__Fields fields;
};
-
-
-
struct Image_1__Fields {
struct MaskableGraphic__Fields _;
struct Sprite* m_CachedSprite;
@@ -11914,6 +11917,24 @@ namespace app {
MonitorData* monitor;
};
+ struct Renderer__Fields {
+ struct Component_1__Fields _;
+ };
+
+ struct Renderer {
+ struct Renderer__Class* klass;
+ MonitorData* monitor;
+ struct Renderer__Fields fields;
+ };
+
+ struct Material__Array {
+ struct Material__Array__Class* klass;
+ MonitorData* monitor;
+ Il2CppArrayBounds* bounds;
+ il2cpp_array_size_t max_length;
+ struct Material* vector[32];
+ };
+
#if !defined(_GHIDRA_) && !defined(_IDA_)
}
#endif
diff --git a/cheat-library/src/user/cheat/cheat.cpp b/cheat-library/src/user/cheat/cheat.cpp
index 3aaa9f8..e08d1f1 100644
--- a/cheat-library/src/user/cheat/cheat.cpp
+++ b/cheat-library/src/user/cheat/cheat.cpp
@@ -49,6 +49,7 @@
#include
#include
#include
+#include
#include "GenshinCM.h"
@@ -109,7 +110,8 @@ namespace cheat
FEAT_INST(PaimonFollow),
FEAT_INST(HideUI),
FEAT_INST(Browser),
- FEAT_INST(EnablePeaking)
+ FEAT_INST(EnablePeaking),
+ FEAT_INST(TextureChanger),
});
#undef FEAT_INST
diff --git a/cheat-library/src/user/cheat/visuals/TextureChanger.cpp b/cheat-library/src/user/cheat/visuals/TextureChanger.cpp
new file mode 100644
index 0000000..36f1c15
--- /dev/null
+++ b/cheat-library/src/user/cheat/visuals/TextureChanger.cpp
@@ -0,0 +1,128 @@
+#include "pch-il2cpp.h"
+#include "TextureChanger.h"
+
+#include
+#include
+#include
+#include
+
+namespace cheat::feature
+{
+ namespace GameObject {
+ app::GameObject* AvatarRoot = nullptr;
+ }
+
+ TextureChanger::TextureChanger() : Feature(),
+ NF(f_Enabled, "Texture Changer", "Visuals::TextureChanger", false),
+ NF(f_HeadPath, "Head", "Visuals::TextureChanger", false),
+ NF(f_BodyPath, "Body", "Visuals::TextureChanger", false),
+ NF(f_DressPath, "Dress", "Visuals::TextureChanger", false),
+ toBeUpdate(), nextUpdate(0)
+ {
+ events::GameUpdateEvent += MY_METHOD_HANDLER(TextureChanger::OnGameUpdate);
+ }
+
+ const FeatureGUIInfo& TextureChanger::GetGUIInfo() const
+ {
+ static const FeatureGUIInfo info{ "TextureChanger", "Visuals", true };
+ return info;
+ }
+
+ void TextureChanger::DrawMain()
+ {
+ ConfigWidget(f_Enabled, "Texture Changer.");
+ ImGui::Text("Active Hero: %s", ActiveHero.c_str());
+
+ ConfigWidget(f_HeadPath, "Head Texture.\n" \
+ "Example path: C:\\Head.png");
+
+ ConfigWidget(f_BodyPath, "Body Texture.\n" \
+ "Example path: C:\\Body.png");
+
+ ConfigWidget(f_DressPath, "Dress Texture.\n" \
+ "Example path: C:\\Dress.png");
+
+ if (ImGui::Button("Apply"))
+ ApplyTexture = true;
+ }
+
+ bool TextureChanger::NeedStatusDraw() const
+ {
+ return f_Enabled;
+ }
+
+ void TextureChanger::DrawStatus()
+ {
+ ImGui::Text("Texture Changer");
+ }
+
+ TextureChanger& TextureChanger::GetInstance()
+ {
+ static TextureChanger instance;
+ return instance;
+ }
+
+ void TextureChanger::OnGameUpdate()
+ {
+ if (!f_Enabled)
+ return;
+
+ auto currentTime = util::GetCurrentTimeMillisec();
+ if (currentTime < nextUpdate)
+ return;
+
+ if (ApplyTexture)
+ {
+ GameObject::AvatarRoot = app::GameObject_Find(string_to_il2cppi("/EntityRoot/AvatarRoot"), nullptr);
+
+ if (GameObject::AvatarRoot != nullptr)
+ {
+ auto Transform = app::GameObject_GetComponentByName(GameObject::AvatarRoot, string_to_il2cppi("Transform"), nullptr);
+ auto HeroCount = app::Transform_get_childCount(reinterpret_cast(Transform), nullptr);
+
+ for (int i = 0; i <= HeroCount - 1; i++)
+ {
+ auto HeroComponent = app::Transform_GetChild(reinterpret_cast(Transform), i, nullptr);
+ auto HeroGameObject = app::Component_1_get_gameObject(reinterpret_cast(HeroComponent), nullptr);
+ auto isActiveHero = app::GameObject_get_active(HeroGameObject, nullptr);
+
+ if (isActiveHero)
+ {
+ auto GameObjectName = app::Object_1_get_name(reinterpret_cast(HeroGameObject), nullptr);
+ ActiveHero = il2cppi_to_string(GameObjectName);
+ auto OffsetDummy = app::GameObject_Find(string_to_il2cppi("/EntityRoot/AvatarRoot/" + il2cppi_to_string(GameObjectName) + "/OffsetDummy"), nullptr);
+ auto TransformOffsetDummy = app::GameObject_GetComponentByName(OffsetDummy, string_to_il2cppi("Transform"), nullptr);
+ auto TransformChildOffsetDummy = app::Transform_GetChild(reinterpret_cast(TransformOffsetDummy), 0, nullptr);
+ auto OffsetGameObject = app::Component_1_get_gameObject(reinterpret_cast(TransformChildOffsetDummy), nullptr);
+ auto OffsetGameObjectName = app::Object_1_get_name(reinterpret_cast(OffsetGameObject), nullptr);
+ auto GameObjectBody = app::GameObject_Find(string_to_il2cppi("/EntityRoot/AvatarRoot/" + il2cppi_to_string(GameObjectName) + "/OffsetDummy/" + il2cppi_to_string(OffsetGameObjectName) + "/Body"), nullptr);
+ auto SkinnedMeshRenderer = app::GameObject_GetComponentByName(reinterpret_cast(GameObjectBody), string_to_il2cppi("SkinnedMeshRenderer"), nullptr);
+ auto Material = app::Renderer_GetMaterialArray(reinterpret_cast(SkinnedMeshRenderer), nullptr);
+ // 0 - Hair, 1 - Body, 2 - Dress
+ if (f_HeadPath && CheckFile(f_HeadPath)) {
+ auto HeadTexture = app::NativeGallery_LoadImageAtPath(string_to_il2cppi(f_HeadPath), 100, false, false, false, nullptr);
+ app::Material_set_mainTexture(Material->vector[0], reinterpret_cast(HeadTexture), nullptr);
+ }
+ if (f_BodyPath && CheckFile(f_BodyPath)) {
+ auto BodyTexture = app::NativeGallery_LoadImageAtPath(string_to_il2cppi(f_BodyPath), 100, false, false, false, nullptr);
+ app::Material_set_mainTexture(Material->vector[1], reinterpret_cast(BodyTexture), nullptr);
+ }
+ if (f_DressPath && CheckFile(f_DressPath)) {
+ auto DressTexture = app::NativeGallery_LoadImageAtPath(string_to_il2cppi(f_DressPath), 100, false, false, false, nullptr);
+
+ if (Material->vector[2] != nullptr)
+ app::Material_set_mainTexture(Material->vector[2], reinterpret_cast(DressTexture), nullptr);
+ }
+ ApplyTexture = false;
+ }
+ }
+ }
+ }
+ nextUpdate = currentTime + (int)f_DelayUpdate;
+ }
+
+ bool TextureChanger::CheckFile(const std::string& Filename) {
+ struct stat buffer;
+ return (stat(Filename.c_str(), &buffer) == 0);
+ }
+}
\ No newline at end of file
diff --git a/cheat-library/src/user/cheat/visuals/TextureChanger.h b/cheat-library/src/user/cheat/visuals/TextureChanger.h
new file mode 100644
index 0000000..934d355
--- /dev/null
+++ b/cheat-library/src/user/cheat/visuals/TextureChanger.h
@@ -0,0 +1,33 @@
+#pragma once
+#include
+#include
+#include
+
+namespace cheat::feature
+{
+ class TextureChanger : public Feature
+ {
+ public:
+ config::Field> f_Enabled;
+ config::Field> f_HeadPath;
+ config::Field> f_BodyPath;
+ config::Field> f_DressPath;
+ std::string ActiveHero = "NONE";
+ bool ApplyTexture;
+
+ static TextureChanger& GetInstance();
+ const FeatureGUIInfo& GetGUIInfo() const override;
+ void DrawMain() override;
+ bool NeedStatusDraw() const override;
+ void DrawStatus() override;
+ bool CheckFile(const std::string& name);
+ private:
+ SafeQueue toBeUpdate;
+ SafeValue nextUpdate;
+ int f_DelayUpdate = 15;
+
+ void OnGameUpdate();
+ TextureChanger();
+
+ };
+}
\ No newline at end of file