diff --git a/src/unlocker/main.cpp b/src/unlocker/main.cpp index 1c799c2..4f2a91f 100644 --- a/src/unlocker/main.cpp +++ b/src/unlocker/main.cpp @@ -295,44 +295,19 @@ int main() if (url.find("api/v1/extensions/store/getCatalogItems") != std::string::npos) updateCatalog(data); - else if (url.find("api/v1/dbd-inventories/all") != std::string::npos) + else if (url.find("api/v1/dbd-inventories/") != std::string::npos) { std::lock_guard lock(g_dataMutex); - if (!g_allObjectIds.empty() || !g_stackableItems.empty() || !g_uniqueItems.empty()) + if (!g_allObjectIds.empty()) { - Log::info("Merging catalog and custom items into real inventory response"); - - std::regex qtyRegex(R"("quantity"\s*:\s*\d+)"); - for (const auto& id : g_stackableItems) - { - size_t pos = data.find("\"objectId\":\"" + id + "\""); - if (pos != std::string::npos) - { - size_t start = data.rfind("{", pos); - size_t end = data.find("}", pos); - if (start != std::string::npos && end != std::string::npos && start < end) - { - std::string objStr = data.substr(start, end - start + 1); - objStr = std::regex_replace(objStr, qtyRegex, "\"quantity\":100"); - data.replace(start, end - start + 1, objStr); - } - } - } + Log::info("Merging catalog items into real inventory response"); size_t closePos = data.rfind("]}"); if (closePos != std::string::npos) { uint64_t now = time(nullptr); std::string injected; - injected.reserve((g_allObjectIds.size() + g_stackableItems.size() + g_uniqueItems.size()) * 60); - - std::unordered_set dbIds; - for (auto& id : g_stackableItems) - dbIds.insert(id); - for (auto& id : g_uniqueItems) - dbIds.insert(id); - for (auto& id : g_perks) - dbIds.insert(id); + injected.reserve(g_allObjectIds.size() * 60); std::unordered_set handledIds; auto injectItem = [&](const std::string& id, int qty) { @@ -351,30 +326,20 @@ int main() handledIds.insert(id); }; - for (const auto& id : g_stackableItems) - injectItem(id, 100); - for (const auto& id : g_uniqueItems) - injectItem(id, 1); - for (const auto& id : g_perks) - injectItem(id, 3); - for (const auto& id : g_allObjectIds) - { - if (dbIds.find(id) == dbIds.end()) injectItem(id, 1); - } + injectItem(id, 1); if (!injected.empty()) data.insert(closePos, injected); - Log::info("Injected {} new items into inventory", + Log::info("Injected {} catalog items into global inventory", injected.empty() ? 0 : std::count(injected.begin(), injected.end(), '{')); } } else - Log::warning("No catalog or custom data available to inject into inventory yet!"); + Log::warning("No catalog data available to inject into global inventory yet!"); } - else if (url.find("api/v1/dbd-character-data/get-all") != std::string::npos) + else if (url.find("api/v1/dbd-character-data/") != std::string::npos) { - std::vector localStackable; std::vector localUnique; std::vector localPerks; @@ -387,33 +352,33 @@ int main() if (!localStackable.empty() || !localUnique.empty() || !localPerks.empty()) { - size_t pos = 0; - size_t count = 0; - std::unordered_set stackableSet(localStackable.begin(), localStackable.end()); - std::unordered_set uniqueSet(localUnique.begin(), localUnique.end()); std::unordered_set perkSet(localPerks.begin(), localPerks.end()); + std::unordered_set uniqueSet(localUnique.begin(), localUnique.end()); + std::regex qtyRegex(R"("quantity"\s*:\s*\d+)"); - while ((pos = data.find("\"characterItems\":[", pos)) != std::string::npos) + const char* targetArrays[] = {"\"characterItems\":[", "\"inventory\":["}; + size_t arraysModified = 0; + + for (const char* arrayKey : targetArrays) { - pos += 18; - - size_t endPos = data.find("]", pos); - if (endPos != std::string::npos) + size_t pos = 0; + while ((pos = data.find(arrayKey, pos)) != std::string::npos) { - std::string currentItems = data.substr(pos, endPos - pos); - std::string newItems; - newItems.reserve(currentItems.size() * 2); + pos += strlen(arrayKey); + size_t endPos = data.find("]", pos); + if (endPos == std::string::npos) break; + std::string currentItems = data.substr(pos, endPos - pos); std::unordered_set seenIds; size_t itemPos = 0; while ((itemPos = currentItems.find("\"itemId\":\"", itemPos)) != std::string::npos) { - itemPos += 10; - size_t quotePos = currentItems.find("\"", itemPos); - if (quotePos == std::string::npos) break; + size_t idStart = itemPos + 10; + size_t idEnd = currentItems.find("\"", idStart); + if (idEnd == std::string::npos) break; - std::string id = currentItems.substr(itemPos, quotePos - itemPos); + std::string id = currentItems.substr(idStart, idEnd - idStart); seenIds.insert(id); int qty = 100; @@ -422,7 +387,22 @@ int main() else if (uniqueSet.count(id)) qty = 1; - newItems += "{\"itemId\":\"" + id + "\",\"quantity\":" + std::to_string(qty) + "},"; + size_t objStart = currentItems.rfind("{", itemPos); + size_t objEnd = currentItems.find("}", itemPos); + if (objStart != std::string::npos && objEnd != std::string::npos && objStart < objEnd) + { + std::string objStr = currentItems.substr(objStart, objEnd - objStart + 1); + if (std::regex_search(objStr, qtyRegex)) + objStr = + std::regex_replace(objStr, qtyRegex, "\"quantity\":" + std::to_string(qty)); + else + objStr.insert(objStr.length() - 1, ",\"quantity\":" + std::to_string(qty)); + + currentItems.replace(objStart, objEnd - objStart + 1, objStr); + itemPos = objStart + objStr.length(); + } + else + itemPos = idEnd; } auto injectIfMissing = [&](const std::vector& list, int qty) { @@ -430,7 +410,9 @@ int main() { if (seenIds.find(id) == seenIds.end()) { - newItems += "{\"itemId\":\"" + id + "\",\"quantity\":" + std::to_string(qty) + "},"; + if (!currentItems.empty() && currentItems.back() != ',') currentItems += ","; + currentItems += + "{\"itemId\":\"" + id + "\",\"quantity\":" + std::to_string(qty) + "}"; seenIds.insert(id); } } @@ -440,19 +422,15 @@ int main() injectIfMissing(localUnique, 1); injectIfMissing(localPerks, 3); - if (!newItems.empty()) newItems.pop_back(); // trailing comma - - data.replace(pos, endPos - pos, newItems); - - endPos = pos + newItems.length(); - pos = endPos; - count++; + data.replace(pos, endPos - pos, currentItems); + pos += currentItems.length(); + arraysModified++; } } - Log::info("Added missing items and targeted perk tiers in {} character inventories", count); + Log::info("Spoofed items in {} character data arrays across response", arraysModified); } else - Log::warning("No custom dumped items available to inject into character inventory!"); + Log::warning("No custom dumped items available to inject into character data!"); } });