feat: update spoofer to reflect new data

This commit is contained in:
2026-04-12 12:42:08 -03:00
parent de418a6568
commit 4559b9d4ec
2 changed files with 90 additions and 99 deletions
+86 -94
View File
@@ -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<std::string>* camperSet,
std::unordered_set<std::string>* slasherSet,
std::unordered_set<std::string>* 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<std::string>& targetSet) {
if (catalogData.contains(key) && catalogData[key].contains("items"))
for (const auto& id : catalogData[key]["items"])
{
if (id.is_string()) targetSet.insert(id.get<std::string>());
}
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<std::string>& camperSet,
std::unordered_set<std::string>& slasherSet)
bool Spoofer::parseStackable(std::string data, std::unordered_set<std::string>* camperSet,
std::unordered_set<std::string>* slasherSet, std::unordered_set<std::string>* 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<std::string>&
return false;
}
auto populate = [&](const std::string& key, std::unordered_set<std::string>& targetSet) {
auto populate = [&](const std::string& key, std::unordered_set<std::string>* targetSet) {
if (doc.contains(key) && doc[key].is_array())
for (const auto& item : doc[key])
{
if (item.is_string()) targetSet.insert(item.get<std::string>());
if (item.is_string()) targetSet->insert(item.get<std::string>());
}
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<std::string>());
}
}
if (doc.contains("Outfits"))
{
for (const auto& outfit : doc["Outfits"])
{
if (outfit.is_string()) _catalogOutfitIds.insert(outfit.get<std::string>());
}
}
return true;
}
@@ -200,8 +210,8 @@ bool Spoofer::parseStackable(std::string data, std::unordered_set<std::string>&
std::string Spoofer::getRandomItem()
{
std::vector<const std::unordered_set<std::string>*> allSets = {
&_camperItemIds, &_slasherPowerIds, &_camperOfferingIds, &_slasherOfferingIds,
&_camperAddonIds, &_slasherAddonIds, &_camperPerkIds, &_slasherPerkIds};
&_camperItemIds, &_camperOfferingIds, &_slasherOfferingIds, &_camperAddonIds,
&_slasherAddonIds, &_camperPerkIds, &_slasherPerkIds};
std::vector<const std::unordered_set<std::string>*> validSets;
for (auto* s : allSets)
@@ -324,6 +334,7 @@ void Spoofer::modifyCharacterData(json& js)
std::unordered_set<std::string> 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);