diff --git a/src/Client/Events/Render/DrawImageEvent.hpp b/src/Client/Events/Render/DrawImageEvent.hpp index a229c92c..3b2c864f 100644 --- a/src/Client/Events/Render/DrawImageEvent.hpp +++ b/src/Client/Events/Render/DrawImageEvent.hpp @@ -3,11 +3,11 @@ #include "../Event.hpp" #include "../Cancellable.hpp" #include "../../../Utils/Utils.hpp" -#include "../../../SDK/Client/Render/Texture2D.hpp" +#include "../../../SDK/Client/Render/TexturePtr.hpp" class DrawImageEvent : public Event, Cancellable { private: - TextureData *texturePtr; + TexturePtr *texturePtr; Vec2 &imagePos; public: [[nodiscard]] Vec2 &getImagePos() const { @@ -18,7 +18,7 @@ class DrawImageEvent : public Event, Cancellable { return this->texturePtr->GetFilePath(); } - explicit DrawImageEvent(TextureData *texturePtr, Vec2 &imagePos) + explicit DrawImageEvent(TexturePtr *texturePtr, Vec2 &imagePos) : texturePtr(texturePtr), imagePos(imagePos) { } }; \ No newline at end of file diff --git a/src/Client/Hook/Hooks/Render/SetupAndRenderHook.hpp b/src/Client/Hook/Hooks/Render/SetupAndRenderHook.hpp index f6d57f48..2e74e100 100644 --- a/src/Client/Hook/Hooks/Render/SetupAndRenderHook.hpp +++ b/src/Client/Hook/Hooks/Render/SetupAndRenderHook.hpp @@ -30,7 +30,7 @@ class SetUpAndRenderHook : public Hook static void drawImageDetour( MinecraftUIRenderContext* _this, - TextureData* texturePtr, + TexturePtr* texturePtr, Vec2& imagePos, Vec2& imageDimension, Vec2& uvPos, @@ -40,7 +40,7 @@ class SetUpAndRenderHook : public Hook DrawImageEvent event(texturePtr, imagePos); EventHandler::onDrawImage(event); - Memory::CallFunc&, Vec2&, Vec2&, Vec2&>( + Memory::CallFunc&, Vec2&, Vec2&, Vec2&>( oDrawImage, _this, texturePtr, @@ -67,7 +67,7 @@ class SetUpAndRenderHook : public Hook static void setUpAndRenderCallback(ScreenView* pScreenView, MinecraftUIRenderContext* muirc) { SDK::screenView = pScreenView; - SDK::clientInstance = muirc->getclientInstance(); + SDK::clientInstance = muirc->getClientInstance(); SDK::hasInstanced = true; if(funcOriginalText == nullptr || oDrawImage == nullptr) diff --git a/src/SDK/Client/Render/BedrockTexture.hpp b/src/SDK/Client/Render/BedrockTexture.hpp new file mode 100644 index 00000000..4338f873 --- /dev/null +++ b/src/SDK/Client/Render/BedrockTexture.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +#include "BedrockTextureData.hpp" + +struct BedrockTexture { +public: + std::shared_ptr bedrockTextureData; + + BedrockTexture() = default; + + BedrockTexture(const BedrockTextureData& data) { + bedrockTextureData = std::make_shared(data); + } + + void unload() { + if(bedrockTextureData != nullptr) { + bedrockTextureData.reset(); + + int newState = bedrockTextureData->textureLoadState & ~TextureLoadState::LoadedBit; + bedrockTextureData->textureLoadState = static_cast(newState); + + bedrockTextureData->isMissingTexture = IsMissingTexture::No; + } + } + + bool operator==(const BedrockTexture& other) const { + if(bedrockTextureData == other.bedrockTextureData) return true; + return bedrockTextureData->clientTexture == other.bedrockTextureData->clientTexture; + } + + bool operator!=(const BedrockTexture& other) const { + if(bedrockTextureData != other.bedrockTextureData) return true; + return bedrockTextureData->clientTexture != other.bedrockTextureData->clientTexture; + } +}; \ No newline at end of file diff --git a/src/SDK/Client/Render/BedrockTextureData.hpp b/src/SDK/Client/Render/BedrockTextureData.hpp new file mode 100644 index 00000000..8b6cb122 --- /dev/null +++ b/src/SDK/Client/Render/BedrockTextureData.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "TexturePtr.hpp" +#include "Textures/mceTextureDescription.hpp" +#include "Textures/ClientTexture.hpp" +#include "Textures/IsMissingTexture.hpp" +#include "Textures/TextureLoadState.hpp" +#include "Textures/TextureSetImageDescription.hpp" + +struct BedrockTextureData { +public: + mce::ClientTexture clientTexture; + mce::TextureDescription textureDescription; + IsMissingTexture isMissingTexture; + TextureLoadState textureLoadState; + cg::TextureSetImageDescription textureSetDescription; + + ~BedrockTextureData() { + clientTexture.resourcePointerBlock.reset(); + textureSetDescription.layerInfo.clear(); + }; +}; \ No newline at end of file diff --git a/src/SDK/Client/Render/MinecraftUIRenderContext.hpp b/src/SDK/Client/Render/MinecraftUIRenderContext.hpp index 4ddf86d1..7ce5e455 100644 --- a/src/SDK/Client/Render/MinecraftUIRenderContext.hpp +++ b/src/SDK/Client/Render/MinecraftUIRenderContext.hpp @@ -11,10 +11,77 @@ #include "../Container/Inventory.hpp" #include "../../../Utils/Utils.hpp" #include "../../../Client/GUI/D2D.hpp" -#include "Texture2D.hpp" +#include "TexturePtr.hpp" +#include "TextureGroup.hpp" +#include "../../../Client/Module/Manager.hpp" class MinecraftUIRenderContext { public: - BUILD_ACCESS(this, ClientInstance*, clientInstance, GET_OFFSET("MinecraftUIRenderContext::clientInstance")); - BUILD_ACCESS(this, class ScreenContext*, screenContext, GET_OFFSET("MinecraftUIRenderContext::screenContext")); + ClientInstance* getClientInstance() { + return hat::member_at(this, GET_OFFSET("MinecraftUIRenderContext::clientInstance")); + } + + class ScreenContext* getScreenContext() { + return hat::member_at(this, GET_OFFSET("MinecraftUIRenderContext::screenContext")); + } + + std::shared_ptr& getTextureGroup() { + return hat::member_at>(this, GET_OFFSET("MinecraftUIRenderContext::textures")); + } + + std::map& getTextures() { + return getTextureGroup()->getLoadedTextures(); + } + + TexturePtr* getTexture(TexturePtr* ptr, const ResourceLocation& location, bool forceReload) { + using getTextureFunc = TexturePtr*(__fastcall*)(MinecraftUIRenderContext*, TexturePtr*, const ResourceLocation&, bool); + static auto getTextureOriginal = reinterpret_cast(Memory::findSig(GET_SIG("MinecraftUIRenderContext::getTexture"))); + return getTextureOriginal(this, ptr, location, forceReload); + } + + TexturePtr* createTexture(const std::string& path, bool external, bool forceReload) { + const auto resource = ResourceLocation(path, external); + TexturePtr texture = TexturePtr(); + return getTexture(&texture, resource, forceReload); + } + + TexturePtr* createTexture(const ResourceLocation& location, bool forceReload) { + TexturePtr texture = TexturePtr(); + return getTexture(&texture, location, forceReload); + } + + void reloadTexture(const ResourceLocation& location) { + this->createTexture(location, true); + } + + void reloadAllTextures() { + auto& textures = this->getTextures(); + + for (auto& [resourceLocation, texture] : textures) { + texture.unload(); + reloadTexture(resourceLocation); + } + } + + void swapTextures(ResourceLocation& from, ResourceLocation& to) { + auto& textures = this->getTextures(); + + // only reload if texture is not loaded + if(!textures.contains(from)) { + reloadTexture(from); + } + + if(!textures.contains(to)) { + reloadTexture(to); + } + + if(textures.contains(from) && textures.contains(to) && textures[from] != textures[to]) { + if(textures[to].bedrockTextureData->textureLoadState == TextureLoadState::LoadedBit) { + textures[from] = textures[to]; + } else { + auto texture = createTexture(to, false); + textures[from] = *texture->clientTexture; + } + } + } }; \ No newline at end of file diff --git a/src/SDK/Client/Render/ResourceLocation.hpp b/src/SDK/Client/Render/ResourceLocation.hpp new file mode 100644 index 00000000..3bbf789b --- /dev/null +++ b/src/SDK/Client/Render/ResourceLocation.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include + +enum ResourceFileSystem : int32_t { + UserPackage = 0x0000, + AppPackage = 0x0001, + Raw = 0x0002, + RawPersistent = 0x0003, + SettingsDir = 0x0004, + ExternalDir = 0x0005, + ServerPackage = 0x0006, + DataDir = 0x0007, + UserDir = 0x0008, + ScreenshotsDir = 0x0009, + StoreCache = 0x000a, + Invalid = 0x000b, +}; + +class ResourceLocation { +public: + ResourceFileSystem fileSystem; + std::string filePath; + uint64_t pathHash{}; + uint64_t fullHash{}; + + ResourceLocation(const std::string& filePath, bool external) { + this->filePath = filePath; + if (external) + this->fileSystem = ResourceFileSystem::Raw; + else this->fileSystem = ResourceFileSystem::UserPackage; + + _computeHashes(); + }; + + bool operator==(const ResourceLocation& other) const { + if(this->fileSystem != other.fileSystem || this->pathHash != other.pathHash) return false; + return this->filePath == other.filePath; + } + + bool operator<(const ResourceLocation& other) const { + return this->filePath < other.filePath; + } + +private: + void _computeHashes() + { + const uint64_t FNV_OFFSET_BASIS = 0xCBF29CE484222325u; + const uint64_t FNV_PRIME = 0x100000001B3u; + + uint64_t _pathHash = FNV_OFFSET_BASIS; + if (!this->filePath.empty()) { + for (char c : this->filePath) { + _pathHash *= FNV_PRIME; + _pathHash ^= c; + } + } else { + _pathHash = 0; + } + + uint64_t fileSystemHash = FNV_OFFSET_BASIS ^ static_cast(this->fileSystem); + fileSystemHash *= FNV_PRIME; + + this->pathHash = _pathHash; + this->fullHash = _pathHash ^ fileSystemHash; + } +}; \ No newline at end of file diff --git a/src/SDK/Client/Render/Texture2D.hpp b/src/SDK/Client/Render/Texture2D.hpp deleted file mode 100644 index e03439b7..00000000 --- a/src/SDK/Client/Render/Texture2D.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include - -class TextureData { -private: - char pad_0x0[0x18]; - struct PathStruct { - char pad_0x0[0x18]; - std::string filePath; - } *ptrToPath; - char pad_0x0038[0x20]; - -public: - [[nodiscard]] std::string GetFilePath() const { - return ptrToPath->filePath; - } -}; \ No newline at end of file diff --git a/src/SDK/Client/Render/TextureGroup.hpp b/src/SDK/Client/Render/TextureGroup.hpp new file mode 100644 index 00000000..d86c49f8 --- /dev/null +++ b/src/SDK/Client/Render/TextureGroup.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include +#include "ResourceLocation.hpp" +#include "../../../Utils/Memory/Game/SignatureAndOffsetManager.hpp" +#include "libhat/Access.hpp" +#include "BedrockTexture.hpp" + +class TextureGroup { +public: + std::map& getLoadedTextures() { + return hat::member_at>(this, GET_OFFSET("TextureGroup::base") + GET_OFFSET("TextureGroup::loadedTextures")); + } +}; \ No newline at end of file diff --git a/src/SDK/Client/Render/TexturePtr.hpp b/src/SDK/Client/Render/TexturePtr.hpp new file mode 100644 index 00000000..955037ac --- /dev/null +++ b/src/SDK/Client/Render/TexturePtr.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include "ResourceLocation.hpp" +#include "BedrockTextureData.hpp" + + +class TexturePtr { +public: + std::shared_ptr clientTexture; + std::shared_ptr resourceLocation; + + TexturePtr() = default; + + [[nodiscard]] std::string GetFilePath() const { + return resourceLocation->filePath; + } +}; \ No newline at end of file diff --git a/src/SDK/Client/Render/Textures/BindFlagsBit.hpp b/src/SDK/Client/Render/Textures/BindFlagsBit.hpp new file mode 100644 index 00000000..1be6f672 --- /dev/null +++ b/src/SDK/Client/Render/Textures/BindFlagsBit.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace mce { + enum BindFlagsBit : uint32_t { + NoBindFlags = 0x0000, + VertexBufferBit = 0x0001, + IndexBufferBit = 0x0002, + ConstantBufferBit = 0x0004, + ShaderResourceBit = 0x0008, + StreamOutputBit = 0x0010, + RenderTargetBit = 0x0020, + DepthStencilBit = 0x0040, + UnorderedAccessBit = 0x0080, + }; +} \ No newline at end of file diff --git a/src/SDK/Client/Render/Textures/ClientTexture.hpp b/src/SDK/Client/Render/Textures/ClientTexture.hpp new file mode 100644 index 00000000..d633ba06 --- /dev/null +++ b/src/SDK/Client/Render/Textures/ClientTexture.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +namespace mce { + class ClientTexture { + public: + std::shared_ptr resourcePointerBlock; + public: + virtual ~ClientTexture() = default; + + bool operator==(const ClientTexture& other) const { + return resourcePointerBlock == other.resourcePointerBlock; + } + + bool operator!=(const ClientTexture& other) const { + return resourcePointerBlock != other.resourcePointerBlock; + } + }; +}; + diff --git a/src/SDK/Client/Render/Textures/Color.hpp b/src/SDK/Client/Render/Textures/Color.hpp new file mode 100644 index 00000000..965ab63e --- /dev/null +++ b/src/SDK/Client/Render/Textures/Color.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace mce { + class Color { // MCCColor + float r; + float g; + float b; + float a; + }; +} diff --git a/src/SDK/Client/Render/Textures/ColorChannel.hpp b/src/SDK/Client/Render/Textures/ColorChannel.hpp new file mode 100644 index 00000000..61cb2dd6 --- /dev/null +++ b/src/SDK/Client/Render/Textures/ColorChannel.hpp @@ -0,0 +1,5 @@ +#pragma once + +class ColorChannel { + float value; +}; \ No newline at end of file diff --git a/src/SDK/Client/Render/Textures/ImageDescription.hpp b/src/SDK/Client/Render/Textures/ImageDescription.hpp new file mode 100644 index 00000000..6305bd86 --- /dev/null +++ b/src/SDK/Client/Render/Textures/ImageDescription.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include +#include "TextureFormat.hpp" + +namespace cg { + struct ImageDescription { + uint32_t width; + uint32_t height; + mce::TextureFormat textureFormat; + uint32_t arraySize; + }; +} \ No newline at end of file diff --git a/src/SDK/Client/Render/Textures/IsMissingTexture.hpp b/src/SDK/Client/Render/Textures/IsMissingTexture.hpp new file mode 100644 index 00000000..5fa37c6f --- /dev/null +++ b/src/SDK/Client/Render/Textures/IsMissingTexture.hpp @@ -0,0 +1,6 @@ +#pragma once + +enum IsMissingTexture : unsigned char { + Yes = 0x0000, + No = 0x0001, +}; \ No newline at end of file diff --git a/src/SDK/Client/Render/Textures/SampleDescription.hpp b/src/SDK/Client/Render/Textures/SampleDescription.hpp new file mode 100644 index 00000000..ffb04d4c --- /dev/null +++ b/src/SDK/Client/Render/Textures/SampleDescription.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace mce { + class SampleDescription { + int32_t count; + int32_t quality; + }; +} \ No newline at end of file diff --git a/src/SDK/Client/Render/Textures/TextureDescription.hpp b/src/SDK/Client/Render/Textures/TextureDescription.hpp new file mode 100644 index 00000000..6ae1cc23 --- /dev/null +++ b/src/SDK/Client/Render/Textures/TextureDescription.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include +#include "ImageDescription.hpp" + +namespace cg { + class TextureDescription : public cg::ImageDescription { + uint32_t mipCount; + }; +} \ No newline at end of file diff --git a/src/SDK/Client/Render/Textures/TextureFormat.hpp b/src/SDK/Client/Render/Textures/TextureFormat.hpp new file mode 100644 index 00000000..e39736ab --- /dev/null +++ b/src/SDK/Client/Render/Textures/TextureFormat.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include + +namespace mce { + enum TextureFormat : uint32_t { + UNKNOWN_TEXTURE_FORMAT = 0x0000, + R32G32B32A32_FLOAT = 0x0002, + R16G16B16A16_FLOAT = 0x000a, + R16G16B16A16_UNORM = 0x000b, + R32G32_FLOAT = 0x0010, + R10G10B10A2_UNORM = 0x0018, + R11G11B10_FLOAT = 0x001a, + R8G8B8A8_UNORM = 0x001c, + R8G8B8A8_UNORM_SRGB = 0x001d, + R16G16_FLOAT = 0x0022, + R16G16_UNORM = 0x0023, + R16G16_UINT = 0x0024, + R16G16_SNORM = 0x0025, + D32_FLOAT = 0x0028, + R32_FLOAT = 0x0029, + R32_UINT = 0x002a, + R24G8_TYPELESS = 0x002c, + D24_UNORM_S8_UINT = 0x002d, + R24_UNORM_X8_TYPELESS = 0x002e, + R8G8_UNORM = 0x0031, + R8G8_SNORM = 0x0033, + R16_FLOAT = 0x0036, + D16_UNORM = 0x0037, + R8_UNORM = 0x003d, + R8_UINT = 0x003e, + A8_UNORM = 0x0041, + BC3_UNORM = 0x004d, + R5G6B5_UNORM = 0x0055, + R5G5B5A1_UNORM = 0x0056, + B8G8R8A8_UNORM = 0x0057, + B8G8R8A8_UNORM_SRGB = 0x005b, + BC7_UNORM = 0x0062, + R4G4B4A4_UNORM = 0x0073, + S8_UINT = 0x0074, + R8G8B8_UNORM = 0x0075, + COMPRESSED = 0x0076, + }; +} \ No newline at end of file diff --git a/src/SDK/Client/Render/Textures/TextureLoadState.hpp b/src/SDK/Client/Render/Textures/TextureLoadState.hpp new file mode 100644 index 00000000..81175ac6 --- /dev/null +++ b/src/SDK/Client/Render/Textures/TextureLoadState.hpp @@ -0,0 +1,9 @@ +#pragma once + +enum TextureLoadState : int { + UnloadedBit = 0x0000, + PendingBit = 0x0001, + LoadedBit = 0x0002, + PendingMetadata = 0x0004, + LoadedMetadata = 0x0008, +}; \ No newline at end of file diff --git a/src/SDK/Client/Render/Textures/TextureSetImageDescription.hpp b/src/SDK/Client/Render/Textures/TextureSetImageDescription.hpp new file mode 100644 index 00000000..b97e5eb5 --- /dev/null +++ b/src/SDK/Client/Render/Textures/TextureSetImageDescription.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include "TextureSetLayerType.hpp" +#include "ImageDescription.hpp" +#include "ColorChannel.hpp" +#include "Color.hpp" + +namespace cg { + class TextureSetImageDescription { + public: + class LayerInfoVar { + cg::TextureSetLayerType layerType; + std::variant data; + }; + + std::vector > layerInfo; + }; +} \ No newline at end of file diff --git a/src/SDK/Client/Render/Textures/TextureSetLayerType.hpp b/src/SDK/Client/Render/Textures/TextureSetLayerType.hpp new file mode 100644 index 00000000..5991b8c4 --- /dev/null +++ b/src/SDK/Client/Render/Textures/TextureSetLayerType.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace cg { + enum TextureSetLayerType : int32_t { + Color = 0x0000, + ColorUnlit = 0x0001, + MER = 0x0002, + Metalness = 0x0003, + Emissive = 0x0004, + Roughness = 0x0005, + Normal = 0x0006, + Heightmap = 0x0007, + }; +} \ No newline at end of file diff --git a/src/SDK/Client/Render/Textures/mceTextureDescription.hpp b/src/SDK/Client/Render/Textures/mceTextureDescription.hpp new file mode 100644 index 00000000..27f297ec --- /dev/null +++ b/src/SDK/Client/Render/Textures/mceTextureDescription.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "TextureDescription.hpp" +#include "SampleDescription.hpp" +#include "Color.hpp" +#include "BindFlagsBit.hpp" + +namespace mce { + class TextureDescription : public cg::TextureDescription { + mce::SampleDescription sampleDescription; + mce::Color clearColor; + float optimizedClearDepth; + unsigned char optimizedClearStencil; + mce::BindFlagsBit bindFlags; + bool isStaging; + }; +} \ No newline at end of file diff --git a/src/Utils/Memory/Game/Sig/SigInit.cpp b/src/Utils/Memory/Game/Sig/SigInit.cpp index d2c75b5c..db00079f 100644 --- a/src/Utils/Memory/Game/Sig/SigInit.cpp +++ b/src/Utils/Memory/Game/Sig/SigInit.cpp @@ -203,6 +203,10 @@ void SigInit::init2030() { ADD_SIG("Tessellator::resetTransform", "80 B9 ? ? ? ? ? 4C 8B C1 75"); ADD_SIG("MeshHelper::renderImmediately", "48 89 5C 24 ? 48 89 74 24 ? 57 48 81 EC ? ? ? ? 49 8B F8 48 8B DA 48 8B F1 80 BA"); + ADD_SIG("MinecraftUIRenderContext::getTexture", "40 53 56 57 48 83 EC 70 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 44 24 60 48 8B DA 48 89"); + + ADD_SIG("mce::TextureGroup::getTexture", "40 53 56 57 48 83 EC 70 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 44 24 60 48 8B DA 48 89"); + ADD_SIG("GuiData::displayClientMessage", "40 55 53 56 57 41 56 48 8D 6C 24 ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 45 ? 41 0F B6 F0"); ADD_SIG("HitResult::getEntity", "E8 ? ? ? ? EB 1A 48 8B CE");