diff --git a/targets/minecraft/client/BufferedImage.cpp b/targets/minecraft/client/BufferedImage.cpp index dff8e52f9..59048b4ef 100644 --- a/targets/minecraft/client/BufferedImage.cpp +++ b/targets/minecraft/client/BufferedImage.cpp @@ -7,9 +7,6 @@ #include #include "PlatformTypes.h" -#include "app/common/DLC/DLCFile.h" -#include "app/common/DLC/DLCManager.h" -#include "app/common/DLC/DLCPack.h" #include "minecraft/IGameServices.h" #include "platform/fs/fs.h" #include "platform/renderer/renderer.h" @@ -121,43 +118,28 @@ BufferedImage::BufferedImage(const std::string& File, bool filenameHasExtension, } } } -BufferedImage::BufferedImage(DLCPack* dlcPack, const std::string& File, - bool filenameHasExtension) { - int32_t hr; - std::string filePath = File; - std::uint8_t* pbData = nullptr; - std::uint32_t dataBytes = 0; +BufferedImage::BufferedImage() { for (int l = 0; l < 10; l++) data[l] = nullptr; + width = 0; + height = 0; +} - for (int l = 0; l < 10; l++) { - std::string name; - std::string mipMapPath = - (l != 0) ? "MipMapLevel" + toWString(l + 1) : ""; - name = "res" + (filenameHasExtension - ? filePath - : filePath.substr(0, filePath.length() - 4) + - mipMapPath + ".png"); - - if (!dlcPack->doesPackContainFile(DLCManager::e_DLCType_All, name)) { - if (l == 0) gameServices().fatalLoadError(); - return; - } - - DLCFile* dlcFile = dlcPack->getFile(DLCManager::e_DLCType_All, name); - pbData = dlcFile->getData(dataBytes); - if (pbData == nullptr || dataBytes == 0) { - if (l == 0) gameServices().fatalLoadError(); - return; - } - - D3DXIMAGE_INFO ImageInfo; - hr = PlatformRenderer.LoadTextureData(pbData, dataBytes, &ImageInfo, - &data[l]); - if (hr == 0 && l == 0) { - width = ImageInfo.Width; - height = ImageInfo.Height; - } +bool BufferedImage::loadMipmapPng(int level, std::uint8_t* bytes, + std::uint32_t numBytes) { + if (level < 0 || level >= 10 || bytes == nullptr || numBytes == 0) { + return false; } + D3DXIMAGE_INFO ImageInfo; + int32_t hr = PlatformRenderer.LoadTextureData(bytes, numBytes, &ImageInfo, + &data[level]); + if (hr != 0) { + return false; + } + if (level == 0) { + width = ImageInfo.Width; + height = ImageInfo.Height; + } + return true; } BufferedImage::BufferedImage(std::uint8_t* pbData, std::uint32_t dataBytes) { diff --git a/targets/minecraft/client/BufferedImage.h b/targets/minecraft/client/BufferedImage.h index a5d04d790..d06d1cd79 100644 --- a/targets/minecraft/client/BufferedImage.h +++ b/targets/minecraft/client/BufferedImage.h @@ -4,7 +4,6 @@ #include class Graphics; -class DLCPack; class BufferedImage { private: @@ -15,15 +14,19 @@ private: public: static const int TYPE_INT_ARGB = 0; static const int TYPE_INT_RGB = 1; + BufferedImage(); // empty image; fill with loadMipmapPng() BufferedImage(int width, int height, int type); BufferedImage(const std::string& File, bool filenameHasExtension = false, bool bTitleUpdateTexture = false, - const std::string& drive = ""); // 4J added - BufferedImage(DLCPack* dlcPack, const std::string& File, - bool filenameHasExtension = false); // 4J Added + const std::string& drive = ""); // 4J added BufferedImage(std::uint8_t* pbData, std::uint32_t dataBytes); // 4J added ~BufferedImage(); + // Decode `numBytes` of PNG-encoded texture data into mipmap slot + // `level`. The first call (level == 0) populates width/height. + // Returns true on success. + bool loadMipmapPng(int level, std::uint8_t* bytes, std::uint32_t numBytes); + int getWidth(); int getHeight(); void getRGB(int startX, int startY, int w, int h, std::vector& out, diff --git a/targets/minecraft/client/Minecraft.cpp b/targets/minecraft/client/Minecraft.cpp index be198d829..6b17606d8 100644 --- a/targets/minecraft/client/Minecraft.cpp +++ b/targets/minecraft/client/Minecraft.cpp @@ -104,7 +104,6 @@ #include "minecraft/client/gui/inventory/CreativeInventoryScreen.h" #endif #include "app/common/ConsoleGameMode.h" -#include "app/common/DLC/DLCPack.h" #include "app/common/Tutorial/FullTutorialMode.h" #include "app/common/UI/All Platforms/IUIScene_CreativeMenu.h" #include "app/common/UI/UIFontData.h" @@ -123,7 +122,7 @@ #include "minecraft/client/player/Input.h" #include "minecraft/client/renderer/texture/TextureManager.h" #include "minecraft/client/resources/Colours/ColourTable.h" -#include "minecraft/client/skins/DLCTexturePack.h" +#include "minecraft/client/skins/TexturePack.h" #include "minecraft/world/entity/npc/Villager.h" #include "minecraft/world/item/alchemy/PotionMacros.h" #include "minecraft/world/level/chunk/SparseDataStorage.h" @@ -1097,18 +1096,8 @@ void Minecraft::run_middle() { TexturePack* tPack = Minecraft::GetInstance() ->skins->getSelected(); - DLCTexturePack* pDLCTexPack = - (DLCTexturePack*)tPack; - - DLCPack* pDLCPack = - pDLCTexPack->getDLCInfoParentPack(); - - if (pDLCPack) { - if (!pDLCPack->hasPurchasedFile( - DLCManager::e_DLCType_Texture, - "")) { - bTrialTexturepack = true; - } + if (tPack->needsPurchase()) { + bTrialTexturepack = true; } } diff --git a/targets/minecraft/client/multiplayer/ClientConnection.cpp b/targets/minecraft/client/multiplayer/ClientConnection.cpp index b96a3a618..7a942b299 100644 --- a/targets/minecraft/client/multiplayer/ClientConnection.cpp +++ b/targets/minecraft/client/multiplayer/ClientConnection.cpp @@ -14,8 +14,6 @@ #include "ReceivingLevelScreen.h" #include "app/common/App_structs.h" #include "app/common/ConsoleGameMode.h" -#include "app/common/DLC/DLCManager.h" -#include "app/common/DLC/DLCPack.h" #include "minecraft/client/skins/ISkinAssetData.h" #include "app/common/Network/Socket.h" #include "app/common/Tutorial/FullTutorialMode.h" @@ -45,7 +43,7 @@ #include "minecraft/client/player/LocalPlayer.h" #include "minecraft/client/player/RemotePlayer.h" #include "minecraft/client/renderer/LevelRenderer.h" -#include "minecraft/client/skins/DLCTexturePack.h" +#include "minecraft/client/skins/TexturePack.h" #include "minecraft/client/skins/TexturePackRepository.h" #include "minecraft/core/particles/ParticleTypes.h" #include "minecraft/network/INetworkService.h" @@ -3456,11 +3454,7 @@ int ClientConnection::HostDisconnectReturned( // world if (!Minecraft::GetInstance()->skins->isUsingDefaultSkin()) { TexturePack* tPack = Minecraft::GetInstance()->skins->getSelected(); - DLCTexturePack* pDLCTexPack = (DLCTexturePack*)tPack; - - DLCPack* pDLCPack = - pDLCTexPack->getDLCInfoParentPack(); // tPack->getDLCPack(); - if (!pDLCPack->hasPurchasedFile(DLCManager::e_DLCType_Texture, "")) { + if (tPack->needsPurchase()) { // no upsell, we're about to quit MinecraftServer::getInstance()->setSaveOnExit(false); // flag a app action of exit game diff --git a/targets/minecraft/client/skins/DLCTexturePack.cpp b/targets/minecraft/client/skins/DLCTexturePack.cpp index 24cdae7cd..36449770b 100644 --- a/targets/minecraft/client/skins/DLCTexturePack.cpp +++ b/targets/minecraft/client/skins/DLCTexturePack.cpp @@ -31,6 +31,7 @@ #include "platform/fs/fs.h" #include "platform/input/input.h" #include "platform/storage/storage.h" +#include "util/StringHelpers.h" #if defined(_WINDOWS64) #endif @@ -192,12 +193,41 @@ std::string DLCTexturePack::getAnimationString(const std::string& textureName, BufferedImage* DLCTexturePack::getImageResource( const std::string& File, bool filenameHasExtension /*= false*/, bool bTitleUpdateTexture /*=false*/, const std::string& drive /*=""*/) { - if (m_dlcDataPack) - return new BufferedImage(m_dlcDataPack, "/" + File, - filenameHasExtension); - else + if (!m_dlcDataPack) { return fallback->getImageResource(File, filenameHasExtension, bTitleUpdateTexture, drive); + } + auto* image = new BufferedImage(); + const std::string filePath = "/" + File; + for (int l = 0; l < 10; l++) { + std::string mipMapPath = + (l != 0) ? "MipMapLevel" + toWString(l + 1) : ""; + std::string name = + "res" + (filenameHasExtension + ? filePath + : filePath.substr(0, filePath.length() - 4) + + mipMapPath + ".png"); + + if (!m_dlcDataPack->doesPackContainFile(DLCManager::e_DLCType_All, + name)) { + if (l == 0) gameServices().fatalLoadError(); + break; + } + + DLCFile* dlcFile = + m_dlcDataPack->getFile(DLCManager::e_DLCType_All, name); + std::uint32_t dataBytes = 0; + std::uint8_t* pbData = dlcFile->getData(dataBytes); + if (pbData == nullptr || dataBytes == 0) { + if (l == 0) gameServices().fatalLoadError(); + break; + } + + if (!image->loadMipmapPng(l, pbData, dataBytes)) { + break; + } + } + return image; } DLCPack* DLCTexturePack::getDLCPack() { return m_dlcDataPack; } @@ -471,3 +501,14 @@ DLCPack* DLCTexturePack::getDLCInfoParentPack() { XCONTENTDEVICEID DLCTexturePack::GetDLCDeviceID() { return m_dlcInfoPack->GetDLCDeviceID(); } + +bool DLCTexturePack::needsPurchase() { + if (m_dlcInfoPack == nullptr) { + return false; + } + DLCPack* parent = m_dlcInfoPack->GetParentPack(); + if (parent == nullptr) { + return false; + } + return !parent->hasPurchasedFile(DLCManager::e_DLCType_Texture, ""); +} diff --git a/targets/minecraft/client/skins/DLCTexturePack.h b/targets/minecraft/client/skins/DLCTexturePack.h index 4c2d860d9..ed9824aa6 100644 --- a/targets/minecraft/client/skins/DLCTexturePack.h +++ b/targets/minecraft/client/skins/DLCTexturePack.h @@ -27,47 +27,47 @@ public: using AbstractTexturePack::getResource; DLCTexturePack(std::uint32_t id, DLCPack* pack, TexturePack* fallback); - ~DLCTexturePack(){}; + ~DLCTexturePack() override = default; - virtual std::string getResource(const std::string& name); - virtual DLCPack* getDLCPack(); - virtual std::string getDesc1() { + std::string getResource(const std::string& name) override; + DLCPack* getDLCPack() override; + std::string getDesc1() override { return m_stringTable->getString("IDS_TP_DESCRIPTION"); } - virtual std::string getName() { + std::string getName() override { return m_stringTable->getString("IDS_DISPLAY_NAME"); } - virtual std::string getWorldName() { + std::string getWorldName() override { return m_stringTable->getString("IDS_WORLD_NAME"); } // Added for sound banks with MashUp packs protected: //@Override - void loadIcon(); - void loadComparison(); - void loadName(); - void loadDescription(); + void loadIcon() override; + void loadComparison() override; + void loadName() override; + void loadDescription() override; InputStream* getResourceImplementation( - const std::string& name); // throws IOException + const std::string& name) override; // throws IOException public: //@Override - bool hasFile(const std::string& name); - bool isTerrainUpdateCompatible(); + bool hasFile(const std::string& name) override; + bool isTerrainUpdateCompatible() override; // 4J Added - virtual std::string getPath(bool bTitleUpdateTexture = false, - const char* pchBDPatchFilename = nullptr); - virtual std::string getAnimationString(const std::string& textureName, - const std::string& path); - virtual BufferedImage* getImageResource(const std::string& File, - bool filenameHasExtension = false, - bool bTitleUpdateTexture = false, - const std::string& drive = ""); - virtual void loadColourTable(); - virtual bool hasData() { return m_bHasLoadedData; } - virtual bool isLoadingData() { return m_bLoadingData; } + std::string getPath(bool bTitleUpdateTexture = false, + const char* pchBDPatchFilename = nullptr) override; + std::string getAnimationString(const std::string& textureName, + const std::string& path) override; + BufferedImage* getImageResource(const std::string& File, + bool filenameHasExtension = false, + bool bTitleUpdateTexture = false, + const std::string& drive = "") override; + void loadColourTable() override; + bool hasData() override { return m_bHasLoadedData; } + bool isLoadingData() override { return m_bLoadingData; } private: static std::string getRootPath(std::uint32_t packId, bool allowOverride, @@ -78,14 +78,16 @@ private: public: int onPackMounted(int iPad, std::uint32_t dwErr, std::uint32_t dwLicenceMask); - virtual void loadData(); - virtual void loadUI(); - virtual void unloadUI(); - virtual std::string getXuiRootPath(); - virtual ArchiveFile* getArchiveFile() { return m_archiveFile; } + void loadData() override; + void loadUI() override; + void unloadUI() override; + std::string getXuiRootPath() override; + ArchiveFile* getArchiveFile() override { return m_archiveFile; } - virtual unsigned int getDLCParentPackId(); + unsigned int getDLCParentPackId() override; virtual DLCPack* getDLCInfoParentPack(); - virtual unsigned char getDLCSubPackId(); + unsigned char getDLCSubPackId() override; XCONTENTDEVICEID GetDLCDeviceID(); + + [[nodiscard]] bool needsPurchase() override; }; diff --git a/targets/minecraft/client/skins/TexturePack.h b/targets/minecraft/client/skins/TexturePack.h index a959b0558..3881ee2ca 100644 --- a/targets/minecraft/client/skins/TexturePack.h +++ b/targets/minecraft/client/skins/TexturePack.h @@ -47,6 +47,12 @@ return TexturePack.class.getResourceAsStream(name); } virtual DLCPack* getDLCPack() { return nullptr; } + // True for trial skins / texture packs that the user has not yet + // purchased. The default (built-in) skin and any owned DLC pack + // returns false. Used by save and disconnect paths to refuse + // operations that would otherwise unlock paid content for free. + [[nodiscard]] virtual bool needsPurchase() { return false; } + // 4J Added virtual std::string getPath(bool bTitleUpdateTexture = false, const char* pchBDPatchFilename = nullptr); diff --git a/targets/minecraft/server/level/ServerLevel.cpp b/targets/minecraft/server/level/ServerLevel.cpp index 3f55b305f..6a493ffa2 100644 --- a/targets/minecraft/server/level/ServerLevel.cpp +++ b/targets/minecraft/server/level/ServerLevel.cpp @@ -11,14 +11,12 @@ #include "ServerChunkCache.h" #include "ServerLevelListener.h" #include "ServerPlayer.h" -#include "app/common/DLC/DLCManager.h" -#include "app/common/DLC/DLCPack.h" #include "java/Class.h" #include "java/Random.h" #include "minecraft/Console_Debug_enum.h" #include "minecraft/IGameServices.h" #include "minecraft/client/Minecraft.h" -#include "minecraft/client/skins/DLCTexturePack.h" +#include "minecraft/client/skins/TexturePack.h" #include "minecraft/client/skins/TexturePackRepository.h" #include "minecraft/network/packet/AddGlobalEntityPacket.h" #include "minecraft/network/packet/EntityEventPacket.h" @@ -981,11 +979,7 @@ void ServerLevel::saveToDisc(ProgressListener* progressListener, // the case for going into the mash-up pack world with a trial version) if (!Minecraft::GetInstance()->skins->isUsingDefaultSkin()) { TexturePack* tPack = Minecraft::GetInstance()->skins->getSelected(); - DLCTexturePack* pDLCTexPack = (DLCTexturePack*)tPack; - - DLCPack* pDLCPack = pDLCTexPack->getDLCInfoParentPack(); - - if (!pDLCPack->hasPurchasedFile(DLCManager::e_DLCType_Texture, "")) { + if (tPack->needsPurchase()) { return; } }