From 7db80484699a74da5af8e686d3e3261550a304aa Mon Sep 17 00:00:00 2001 From: neru Date: Mon, 13 Apr 2026 01:07:53 -0300 Subject: [PATCH] feat: add DLC unlocking --- src/unlocker/spoofing.cpp | 86 +++++++++++++++++++++++++++++++++++++++ src/unlocker/spoofing.h | 11 ++++- 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/unlocker/spoofing.cpp b/src/unlocker/spoofing.cpp index d412ab8..e6f6c64 100644 --- a/src/unlocker/spoofing.cpp +++ b/src/unlocker/spoofing.cpp @@ -121,6 +121,27 @@ void Spoofer::loadData() } } + /* + dlcs + */ + std::ifstream dlcFile(utils::getExePath() + "dlcs.json"); + if (dlcFile.is_open()) + { + std::stringstream buff; + buff << dlcFile.rdbuf(); + json doc = json::parse(buff.str(), nullptr, false); + if (doc.is_discarded()) + Log::error("Failed to parse dlcs.json"); + else + { + for (const auto& dlc : doc) + { + if (dlc.contains("grdk")) _dlcListGRDK.insert(dlc["grdk"].get()); + if (dlc.contains("egs")) _dlcListEGS.insert(dlc["egs"].get()); + } + } + } + Log::verbose("Finished loading data"); Log::verbose("Items - {} camper", _camperItemIds.size()); @@ -131,6 +152,7 @@ void Spoofer::loadData() Log::verbose("Catalog - {} outfits | {} items", _catalogOutfitIds.size(), _catalogItemIds.size()); Log::verbose("Characters - {}", _characterList.size()); + Log::verbose("DLCs - GRDK {} - EGS: {}", _dlcListGRDK.size(), _dlcListEGS.size()); } void Spoofer::loadConfig() @@ -658,6 +680,66 @@ void Spoofer::onBloodweb(std::string& body, std::string& respHeaders) #endif } +void Spoofer::onUpdateEntitlements(const std::string& url, std::string& body) +{ + if (!_config.spoofCharacterOwnership) return; + + json js = json::parse(body, nullptr, false); + if (js.is_discarded()) return Log::error("JSON parse error for get-update-entitlements"); + + if (js.contains("entitlements")) + { + auto& jsonList = js["entitlements"]; + + std::unordered_set* list = nullptr; + + if (url.starts_with("https://grdk.live.bhvrdbd.com/")) + list = &_dlcListGRDK; + else if (url.starts_with("https://egs.live.bhvrdbd.com/")) + list = &_dlcListEGS; + else + return Log::error("Invalid url?"); + + if (list == nullptr) return; + for (const std::string& dlcId : *list) + { + if (std::find(jsonList.begin(), jsonList.end(), dlcId) == jsonList.end()) jsonList.push_back(dlcId); + } + } + + body = js.dump(); +} + +void Spoofer::onUpdateEntitlementsClient(const std::string& url, std::string& body) +{ + if (!_config.spoofCharacterOwnership) return; + + json js = json::parse(body, nullptr, false); + if (js.is_discarded()) return Log::error("JSON parse error for get-update-entitlements"); + + if (js.contains("clientEntitlementIds")) + { + auto& jsonList = js["clientEntitlementIds"]; + + std::unordered_set* list = nullptr; + + if (url.starts_with("https://grdk.live.bhvrdbd.com/")) + list = &_dlcListGRDK; + else if (url.starts_with("https://egs.live.bhvrdbd.com/")) + list = &_dlcListEGS; + else + return Log::error("Invalid url?"); + + if (list == nullptr) return; + for (const std::string& dlcId : *list) + { + if (std::find(jsonList.begin(), jsonList.end(), dlcId) == jsonList.end()) jsonList.push_back(dlcId); + } + } + + body = js.dump(); +} + /* event handlers */ @@ -676,6 +758,8 @@ void Spoofer::serverResponseHandler(const std::string& url, std::string& body, s if (url.find("api/v1/dbd-character-data/bloodweb") != std::string::npos || url.find("api/v1/dbd-character-data/bulk-spending-bloodweb") != std::string::npos) return onBloodweb(body, respHeaders); + + if (url.ends_with("api/v1/owned-products/get-update-entitlements")) return onUpdateEntitlements(url, body); } void Spoofer::clientRequestHandler(const std::string& url, std::string& body, std::string& /*reqHeaders*/) @@ -687,4 +771,6 @@ void Spoofer::clientRequestHandler(const std::string& url, std::string& body, st if (url.find("api/v1/dbd-character-data/bloodweb") != std::string::npos || url.find("api/v1/dbd-character-data/bulk-spending-bloodweb") != std::string::npos) return onBloodwebClient(body); + + if (url.ends_with("api/v1/owned-products/get-update-entitlements")) return onUpdateEntitlementsClient(url, body); } diff --git a/src/unlocker/spoofing.h b/src/unlocker/spoofing.h index 089c6ea..4113798 100644 --- a/src/unlocker/spoofing.h +++ b/src/unlocker/spoofing.h @@ -40,12 +40,16 @@ class Spoofer void generateBloodweb(nlohmann::json& data); void modifyCharacterData(nlohmann::json& js); - void onGetAllClient(std::string& body); void onGetAll(std::string& body); void onInventoryAll(std::string& body); void onMessageList(std::string& body); - void onBloodwebClient(std::string& body); void onBloodweb(std::string& body, std::string& respHeaders); + void onGameConfigs(std::string& body); + void onUpdateEntitlements(const std::string& url, std::string& body); + + void onGetAllClient(std::string& body); + void onBloodwebClient(std::string& body); + void onUpdateEntitlementsClient(const std::string& url, std::string& body); void serverResponseHandler(const std::string& url, std::string& body, std::string& respHeaders); void clientRequestHandler(const std::string& url, std::string& body, std::string& reqHeaders); @@ -70,6 +74,9 @@ class Spoofer std::unordered_set _unownedCharacters; std::unordered_set _characterList; + std::unordered_set _dlcListGRDK; + std::unordered_set _dlcListEGS; + std::string _lastBloodWebChar = ""; std::mutex _mtx; };