diff --git a/src/unlocker/spoofing.cpp b/src/unlocker/spoofing.cpp index ed1f831..2c673b3 100644 --- a/src/unlocker/spoofing.cpp +++ b/src/unlocker/spoofing.cpp @@ -56,41 +56,60 @@ void Spoofer::registerListeners(Proxy* proxy) }); } -#define LOADDATA(fileName, type, camperSet, slasherSet, errorMsg) \ - std::string path##type = utils::getExePath() + fileName; \ - std::ifstream file##type(path##type); \ - if (file##type.is_open()) \ - { \ - std::stringstream buff; \ - buff << file##type.rdbuf(); \ - if (!parseStackable(buff.str(), camperSet, slasherSet)) \ - Log::error("Failed to parse {} - {}", fileName, errorMsg); \ - else \ - Log::verbose("Loaded {} camper ids and {} slasher ids from {}", camperSet.size(), slasherSet.size(), \ - fileName); \ - } \ - else \ - Log::warning("Missing {} - {}", fileName, errorMsg); - void Spoofer::loadData() { Log::info("Loading data"); - std::string catalogPath = utils::getExePath() + "catalog.json"; - std::ifstream catalogFile(catalogPath); - if (catalogFile.is_open()) + /* + stackables + */ + static auto loadData = [this](const char* fileName, std::unordered_set* camperSet, + std::unordered_set* slasherSet, + std::unordered_set* globalSet, const char* errorMsg) { + std::ifstream file(utils::getExePath() + fileName); + + if (file.is_open()) + { + std::stringstream buff; + buff << file.rdbuf(); + if (!parseStackable(buff.str(), camperSet, slasherSet, globalSet)) + return Log::error("Failed to parse {} - {}", fileName, errorMsg); + else + Log::verbose("Loaded {}", fileName); + } + else + Log::warning("Missing file: {} - {}", fileName, errorMsg); + }; + + loadData("items.json", &_camperItemIds, 0, 0, "Items wont be added"); + loadData("offerings.json", &_camperOfferingIds, &_slasherOfferingIds, &_globalOfferingIds, + "Offerings won't be added"); + loadData("addons.json", &_camperAddonIds, &_slasherAddonIds, 0, "Offerings won't be added"); + loadData("perks.json", &_camperPerkIds, &_slasherPerkIds, 0, "Offerings won't be added"); + + /* + catalog items + */ + std::ifstream customizationsFile(utils::getExePath() + "customizations.json"); + if (customizationsFile.is_open()) { std::stringstream buff; - buff << catalogFile.rdbuf(); - if (!parseCatalog(buff.str())) Log::warning("Failed to parse catalog.json - Customizations won't be unlocked"); + buff << customizationsFile.rdbuf(); + if (!parseCustomizations(buff.str())) + Log::warning("Failed to parse customizations.json - Outfits and character items won't be added"); + else + Log::verbose("Loaded customizations.json"); } - else - Log::warning("Missing catalog.json - Customizations won't be unlocked"); - LOADDATA("items.json", Items, _camperItemIds, _slasherPowerIds, "Items won't be added"); - LOADDATA("offerings.json", Offerings, _camperOfferingIds, _slasherOfferingIds, "Offerings won't be added"); - LOADDATA("addons.json", Addons, _camperAddonIds, _slasherAddonIds, "Addons won't be added"); - LOADDATA("perks.json", Perks, _camperPerkIds, _slasherPerkIds, "Perks won't be added"); + Log::verbose("Finished loading data"); + + Log::verbose("Items - {} camper", _camperItemIds.size()); + Log::verbose("Offerings - {} camper | {} slasher | {} global", _camperOfferingIds.size(), + _slasherOfferingIds.size(), _globalOfferingIds.size()); + Log::verbose("Addons - {} camper | {} slasher ", _camperAddonIds.size(), _slasherAddonIds.size()); + Log::verbose("Perks - {} camper | {} slasher ", _camperPerkIds.size(), _slasherPerkIds.size()); + + Log::verbose("Catalog - {} outfits | {} items", _catalogOutfitIds.size(), _catalogItemIds.size()); } void Spoofer::loadConfig() @@ -130,46 +149,8 @@ void Spoofer::loadConfig() /* data parsing */ -bool Spoofer::parseCatalog(std::string data) -{ - json doc = json::parse(data, nullptr, false); - - if (doc.is_discarded()) - { - Log::error("Failed to parse catalog"); - return false; - } - - try - { - const auto& catalogData = doc.at("data"); - - auto extractIds = [&](const std::string& key, std::unordered_set& targetSet) { - if (catalogData.contains(key) && catalogData[key].contains("items")) - for (const auto& id : catalogData[key]["items"]) - { - if (id.is_string()) targetSet.insert(id.get()); - } - else - Log::warning("Catalog missing or invalid category: {}", key); - }; - - extractIds("item", _catalogItemIds); - extractIds("outfit", _catalogOutfitIds); - } - catch (const json::exception& e) - { - Log::error("Invalid catalog format: {}", e.what()); - return false; - } - - Log::info("Parsed {} items and {} outfits from catalog", _catalogItemIds.size(), _catalogOutfitIds.size()); - - return true; -} - -bool Spoofer::parseStackable(std::string data, std::unordered_set& camperSet, - std::unordered_set& slasherSet) +bool Spoofer::parseStackable(std::string data, std::unordered_set* camperSet, + std::unordered_set* slasherSet, std::unordered_set* globalSet) { json doc = json::parse(data, nullptr, false); if (doc.is_discarded()) @@ -178,18 +159,47 @@ bool Spoofer::parseStackable(std::string data, std::unordered_set& return false; } - auto populate = [&](const std::string& key, std::unordered_set& targetSet) { + auto populate = [&](const std::string& key, std::unordered_set* targetSet) { if (doc.contains(key) && doc[key].is_array()) for (const auto& item : doc[key]) { - if (item.is_string()) targetSet.insert(item.get()); + if (item.is_string()) targetSet->insert(item.get()); } else Log::warning("Missing stackables array ({})", key); }; - populate("Slashers", slasherSet); - populate("Campers", camperSet); + if (camperSet) populate("Campers", camperSet); + if (slasherSet) populate("Slashers", slasherSet); + if (globalSet) populate("All", globalSet); + + return true; +} + +bool Spoofer::parseCustomizations(std::string data) +{ + json doc = json::parse(data, nullptr, false); + if (doc.is_discarded()) + { + Log::error("JSON parse error @ parseCustomizations"); + return false; + } + + if (doc.contains("Items")) + { + for (const auto& item : doc["Items"]) + { + if (item.is_string()) _catalogItemIds.insert(item.get()); + } + } + + if (doc.contains("Outfits")) + { + for (const auto& outfit : doc["Outfits"]) + { + if (outfit.is_string()) _catalogOutfitIds.insert(outfit.get()); + } + } return true; } @@ -200,8 +210,8 @@ bool Spoofer::parseStackable(std::string data, std::unordered_set& std::string Spoofer::getRandomItem() { std::vector*> allSets = { - &_camperItemIds, &_slasherPowerIds, &_camperOfferingIds, &_slasherOfferingIds, - &_camperAddonIds, &_slasherAddonIds, &_camperPerkIds, &_slasherPerkIds}; + &_camperItemIds, &_camperOfferingIds, &_slasherOfferingIds, &_camperAddonIds, + &_slasherAddonIds, &_camperPerkIds, &_slasherPerkIds}; std::vector*> validSets; for (auto* s : allSets) @@ -324,6 +334,7 @@ void Spoofer::modifyCharacterData(json& js) std::unordered_set stackableIds; stackableIds.insert(_camperItemIds.begin(), _camperItemIds.end()); stackableIds.insert(_camperOfferingIds.begin(), _camperOfferingIds.end()); + stackableIds.insert(_globalOfferingIds.begin(), _globalOfferingIds.end()); stackableIds.insert(_camperAddonIds.begin(), _camperAddonIds.end()); stackableIds.insert(_slasherAddonIds.begin(), _slasherAddonIds.end()); stackableIds.insert(_slasherOfferingIds.begin(), _slasherOfferingIds.end()); @@ -361,6 +372,8 @@ void Spoofer::modifyCharacterData(json& js) appendItems(_slasherOfferingIds, false); appendItems(_slasherPerkIds, true); } + + appendItems(_globalOfferingIds, true); } } @@ -372,26 +385,6 @@ void Spoofer::modifyCharacterData(json& js) /* endpoint handlers */ - -void Spoofer::onGetCatalogItems(std::string& body) -{ - std::thread t([body]() { - std::string outPath = utils::getExePath() + "catalog.json"; - std::ofstream file(outPath); - if (file.is_open()) - { - file << body; - file.close(); - Log::verbose("Raw catalog saved to {}", outPath); - } - else - Log::error("Unable to write to catalog.json"); - }); - t.detach(); - - parseCatalog(body); -} - void Spoofer::onGetAll(std::string& body) { json doc = json::parse(body, nullptr, false); @@ -624,7 +617,6 @@ void Spoofer::serverResponseHandler(const std::string& url, std::string& body, s Log::verbose("BHVR api res @ {}", url); #endif - if (url.find("api/v1/extensions/store/getCatalogItems") != std::string::npos) return onGetCatalogItems(body); if (url.find("api/v1/dbd-character-data/get-all") != std::string::npos) return onGetAll(body); if (url.find("api/v1/dbd-character-data/get-all") != std::string::npos) return onGetAll(body); if (url.find("api/v1/dbd-inventories/all") != std::string::npos) return onInventoryAll(body); diff --git a/src/unlocker/spoofing.h b/src/unlocker/spoofing.h index ce6feab..c0cc716 100644 --- a/src/unlocker/spoofing.h +++ b/src/unlocker/spoofing.h @@ -26,9 +26,9 @@ class Spoofer void loadData(); void loadConfig(); - bool parseCatalog(std::string data); - bool parseStackable(std::string data, std::unordered_set& camperSet, - std::unordered_set& slasherSet); + bool parseStackable(std::string data, std::unordered_set* camperSet, + std::unordered_set* slasherSet, std::unordered_set* globalSet); + bool parseCustomizations(std::string data); std::string getRandomItem(); int getRandomQuantity(); @@ -36,7 +36,6 @@ class Spoofer void generateBloodweb(nlohmann::json& data); void modifyCharacterData(nlohmann::json& js); - void onGetCatalogItems(std::string& body); void onGetAll(std::string& body); void onInventoryAll(std::string& body); void onMessageList(std::string& body); @@ -48,10 +47,10 @@ class Spoofer SpooferConfig _config; std::unordered_set _camperItemIds; - std::unordered_set _slasherPowerIds; std::unordered_set _camperOfferingIds; std::unordered_set _slasherOfferingIds; + std::unordered_set _globalOfferingIds; std::unordered_set _camperAddonIds; std::unordered_set _slasherAddonIds;