feat: add config
This commit is contained in:
+146
-82
@@ -39,6 +39,7 @@ void Spoofer::init(Proxy* proxy)
|
|||||||
{
|
{
|
||||||
registerListeners(proxy);
|
registerListeners(proxy);
|
||||||
loadData();
|
loadData();
|
||||||
|
loadConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spoofer::registerListeners(Proxy* proxy)
|
void Spoofer::registerListeners(Proxy* proxy)
|
||||||
@@ -90,6 +91,37 @@ void Spoofer::loadData()
|
|||||||
LOADDATA("perks.json", Perks, _camperPerkIds, _slasherPerkIds, "Perks won't be added");
|
LOADDATA("perks.json", Perks, _camperPerkIds, _slasherPerkIds, "Perks won't be added");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Spoofer::loadConfig()
|
||||||
|
{
|
||||||
|
std::string configPath = utils::getExePath() + "config.json";
|
||||||
|
std::ifstream configFile(configPath);
|
||||||
|
|
||||||
|
if (configFile.is_open())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
json configJson = json::parse(configFile);
|
||||||
|
_config.spoofCharacterOwnership = configJson.value("spoofCharacterOwnership", false);
|
||||||
|
_config.spoofInventory = configJson.value("spoofInventory", true);
|
||||||
|
_config.spoofCustomization = configJson.value("spoofCustomization", true);
|
||||||
|
Log::info("Loaded config: Ownership={}, Inventory={}, Customization={}", _config.spoofCharacterOwnership,
|
||||||
|
_config.spoofInventory, _config.spoofCustomization);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
Log::error("Failed to parse config.json, using defaults");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log::info("config.json not found, using default settings");
|
||||||
|
json defaultConfig = {
|
||||||
|
{"spoofCharacterOwnership", true}, {"spoofInventory", true}, {"spoofCustomization", true}};
|
||||||
|
std::ofstream out(configPath);
|
||||||
|
out << defaultConfig.dump(4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
data parsing
|
data parsing
|
||||||
*/
|
*/
|
||||||
@@ -241,81 +273,94 @@ void Spoofer::modifyCharacterData(json& js)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string name = js["characterName"];
|
std::string name = js["characterName"];
|
||||||
bool slasher = isSlasher(js["characterName"]);
|
|
||||||
|
|
||||||
bool needsSpoofing = false;
|
if (_config.spoofCharacterOwnership)
|
||||||
if (js.value("isEntitled", true) == false)
|
|
||||||
{
|
{
|
||||||
_unownedCharacters.insert(name);
|
bool needsSpoofing = false;
|
||||||
js["isEntitled"] = true;
|
|
||||||
js["purchaseInfo"] = {{"quantity", 1},
|
if (js.value("isEntitled", false) == false)
|
||||||
{"origin", "PlayerInventory"},
|
{
|
||||||
{"reason", "Item(s) added via Purchase"},
|
_unownedCharacters.insert(name);
|
||||||
{"lastUpdateAt", std::time(nullptr)},
|
js["isEntitled"] = true;
|
||||||
{"objectId", name}};
|
js["purchaseInfo"] = {{"quantity", 1},
|
||||||
needsSpoofing = true;
|
{"origin", "PlayerInventory"},
|
||||||
|
{"reason", "Item(s) added via Purchase"},
|
||||||
|
{"lastUpdateAt", std::time(nullptr)},
|
||||||
|
{"objectId", name}};
|
||||||
|
needsSpoofing = true;
|
||||||
|
}
|
||||||
|
else if (_unownedCharacters.contains(name))
|
||||||
|
needsSpoofing = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
modifications for unowned characters (spoof level and fake bloodweb)
|
||||||
|
*/
|
||||||
|
if (needsSpoofing)
|
||||||
|
{
|
||||||
|
if (js.contains("bloodWebLevel") && js["bloodWebLevel"].is_number() && js["bloodWebLevel"] <= 15)
|
||||||
|
if (!js.contains("prestigeLevel") || (js["prestigeLevel"].is_number() && js["prestigeLevel"] <= 0))
|
||||||
|
js["bloodWebLevel"] = 16;
|
||||||
|
|
||||||
|
if (js.contains("bloodWebData")) generateBloodweb(js["bloodWebData"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (_unownedCharacters.contains(name))
|
else
|
||||||
needsSpoofing = true;
|
|
||||||
|
|
||||||
/*
|
|
||||||
modifications for unowned characters (spoof level and fake bloodweb)
|
|
||||||
*/
|
|
||||||
if (needsSpoofing)
|
|
||||||
{
|
{
|
||||||
if (js.contains("bloodWebLevel") && js["bloodWebLevel"].is_number() && js["bloodWebLevel"] <= 15)
|
if (js.value("isEntitled", false) == false) return;
|
||||||
if (!js.contains("prestigeLevel") || (js["prestigeLevel"].is_number() && js["prestigeLevel"] <= 0))
|
|
||||||
js["bloodWebLevel"] = 16;
|
|
||||||
|
|
||||||
if (js.contains("bloodWebData")) generateBloodweb(js["bloodWebData"]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
item spoofing
|
item spoofing
|
||||||
*/
|
*/
|
||||||
if (js.contains("characterItems") && js["characterItems"].is_array())
|
if (_config.spoofInventory)
|
||||||
{
|
{
|
||||||
std::unordered_set<std::string> existingItemIds;
|
bool slasher = isSlasher(js["characterName"]);
|
||||||
|
|
||||||
std::unordered_set<std::string> stackableIds;
|
if (js.contains("characterItems") && js["characterItems"].is_array())
|
||||||
stackableIds.insert(_camperItemIds.begin(), _camperItemIds.end());
|
|
||||||
stackableIds.insert(_camperOfferingIds.begin(), _camperOfferingIds.end());
|
|
||||||
stackableIds.insert(_camperAddonIds.begin(), _camperAddonIds.end());
|
|
||||||
stackableIds.insert(_slasherAddonIds.begin(), _slasherAddonIds.end());
|
|
||||||
stackableIds.insert(_slasherOfferingIds.begin(), _slasherOfferingIds.end());
|
|
||||||
|
|
||||||
for (auto& item : js["characterItems"])
|
|
||||||
{
|
{
|
||||||
/*
|
std::unordered_set<std::string> existingItemIds;
|
||||||
|
|
||||||
|
std::unordered_set<std::string> stackableIds;
|
||||||
|
stackableIds.insert(_camperItemIds.begin(), _camperItemIds.end());
|
||||||
|
stackableIds.insert(_camperOfferingIds.begin(), _camperOfferingIds.end());
|
||||||
|
stackableIds.insert(_camperAddonIds.begin(), _camperAddonIds.end());
|
||||||
|
stackableIds.insert(_slasherAddonIds.begin(), _slasherAddonIds.end());
|
||||||
|
stackableIds.insert(_slasherOfferingIds.begin(), _slasherOfferingIds.end());
|
||||||
|
|
||||||
|
for (auto& item : js["characterItems"])
|
||||||
|
{
|
||||||
|
/*
|
||||||
set existing items to rnd number
|
set existing items to rnd number
|
||||||
*/
|
*/
|
||||||
if (item.contains("itemId") && item["itemId"].is_string())
|
if (item.contains("itemId") && item["itemId"].is_string())
|
||||||
{
|
{
|
||||||
std::string itemId = item["itemId"];
|
std::string itemId = item["itemId"];
|
||||||
existingItemIds.insert(itemId);
|
existingItemIds.insert(itemId);
|
||||||
if (stackableIds.contains(itemId)) item["quantity"] = getRandomQuantity();
|
if (stackableIds.contains(itemId)) item["quantity"] = getRandomQuantity();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
auto appendItems = [&](const std::unordered_set<std::string>& idList, bool isPerk) {
|
auto appendItems = [&](const std::unordered_set<std::string>& idList, bool isPerk) {
|
||||||
for (const auto& itemId : idList)
|
for (const auto& itemId : idList)
|
||||||
if (existingItemIds.find(itemId) == existingItemIds.end())
|
if (existingItemIds.find(itemId) == existingItemIds.end())
|
||||||
js["characterItems"].push_back(
|
js["characterItems"].push_back(
|
||||||
{{"itemId", itemId}, {"quantity", isPerk ? 3 : getRandomQuantity()}});
|
{{"itemId", itemId}, {"quantity", isPerk ? 3 : getRandomQuantity()}});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!slasher)
|
if (!slasher)
|
||||||
{
|
{
|
||||||
appendItems(_camperItemIds, false);
|
appendItems(_camperItemIds, false);
|
||||||
appendItems(_camperAddonIds, false);
|
appendItems(_camperAddonIds, false);
|
||||||
appendItems(_camperOfferingIds, false);
|
appendItems(_camperOfferingIds, false);
|
||||||
appendItems(_camperPerkIds, true);
|
appendItems(_camperPerkIds, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
appendItems(_slasherAddonIds, false);
|
appendItems(_slasherAddonIds, false);
|
||||||
appendItems(_slasherOfferingIds, false);
|
appendItems(_slasherOfferingIds, false);
|
||||||
appendItems(_slasherPerkIds, true);
|
appendItems(_slasherPerkIds, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,8 +425,24 @@ void Spoofer::onInventoryAll(std::string& body)
|
|||||||
int quantity;
|
int quantity;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Category> categories = {{_camperPerkIds, 3}, {_slasherPerkIds, 3}, {_camperOfferingIds, -1},
|
std::vector<Category> categories;
|
||||||
{_slasherOfferingIds, -1}, {_catalogOutfitIds, 1}, {_catalogItemIds, 1}};
|
if (_config.spoofInventory)
|
||||||
|
{
|
||||||
|
categories.push_back({_camperPerkIds, 3});
|
||||||
|
categories.push_back({_slasherPerkIds, 3});
|
||||||
|
categories.push_back({_camperOfferingIds, -1});
|
||||||
|
categories.push_back({_slasherOfferingIds, -1});
|
||||||
|
|
||||||
|
categories.push_back({_camperItemIds, -1});
|
||||||
|
categories.push_back({_camperAddonIds, -1});
|
||||||
|
categories.push_back({_slasherAddonIds, -1});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_config.spoofCustomization)
|
||||||
|
{
|
||||||
|
categories.push_back({_catalogOutfitIds, 1});
|
||||||
|
categories.push_back({_catalogItemIds, 1});
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& item : itemsArr)
|
for (auto& item : itemsArr)
|
||||||
{
|
{
|
||||||
@@ -481,36 +542,39 @@ void Spoofer::onBloodweb(std::string& body, std::string& respHeaders)
|
|||||||
json doc = json::parse(body, nullptr, false);
|
json doc = json::parse(body, nullptr, false);
|
||||||
if (doc.is_discarded()) return Log::error("JSON parse error for bloodweb response");
|
if (doc.is_discarded()) return Log::error("JSON parse error for bloodweb response");
|
||||||
|
|
||||||
if (body.find("NotAllowedException") != std::string::npos && body.find("not owned") != std::string::npos)
|
if (_config.spoofCharacterOwnership)
|
||||||
{
|
{
|
||||||
Log::info("Spoofing bloodweb error for unowned character");
|
if (body.find("NotAllowedException") != std::string::npos && body.find("not owned") != std::string::npos)
|
||||||
json mock;
|
{
|
||||||
mock["bloodWebLevelChanged"] = false;
|
Log::info("Spoofing bloodweb error for unowned character");
|
||||||
mock["updatedWallets"] = json::array();
|
json mock;
|
||||||
mock["bloodWebLevel"] = 16;
|
mock["bloodWebLevelChanged"] = false;
|
||||||
mock["prestigeLevel"] = 0;
|
mock["updatedWallets"] = json::array();
|
||||||
mock["bloodWebData"] = json::object();
|
mock["bloodWebLevel"] = 16;
|
||||||
mock["characterItems"] = json::array();
|
mock["prestigeLevel"] = 0;
|
||||||
mock["characterName"] = this->_lastBloodWebChar;
|
mock["bloodWebData"] = json::object();
|
||||||
mock["isEntitled"] = true;
|
mock["characterItems"] = json::array();
|
||||||
mock["purchaseInfo"] = {{"quantity", 1},
|
mock["characterName"] = this->_lastBloodWebChar;
|
||||||
{"origin", "PlayerInventory"},
|
mock["isEntitled"] = true;
|
||||||
{"reason", "Item(s) added via Purchase"},
|
mock["purchaseInfo"] = {{"quantity", 1},
|
||||||
{"lastUpdateAt", std::time(nullptr)},
|
{"origin", "PlayerInventory"},
|
||||||
{"objectId", this->_lastBloodWebChar}};
|
{"reason", "Item(s) added via Purchase"},
|
||||||
|
{"lastUpdateAt", std::time(nullptr)},
|
||||||
|
{"objectId", this->_lastBloodWebChar}};
|
||||||
|
|
||||||
_unownedCharacters.insert(this->_lastBloodWebChar); // probably not needed but just in case
|
_unownedCharacters.insert(this->_lastBloodWebChar); // probably not needed but just in case
|
||||||
|
|
||||||
modifyCharacterData(mock);
|
modifyCharacterData(mock);
|
||||||
|
|
||||||
std::regex statusRegex(R"(HTTP\/\d\.\d\s+403)");
|
std::regex statusRegex(R"(HTTP\/\d\.\d\s+403)");
|
||||||
respHeaders = std::regex_replace(respHeaders, statusRegex, "HTTP/1.1 200");
|
respHeaders = std::regex_replace(respHeaders, statusRegex, "HTTP/1.1 200");
|
||||||
|
|
||||||
body = mock.dump();
|
body = mock.dump();
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
Log::verbose("Spoofed bloodweb request for unowned character.");
|
Log::verbose("Spoofed bloodweb request for unowned character.");
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
modifyCharacterData(doc);
|
modifyCharacterData(doc);
|
||||||
|
|||||||
@@ -9,6 +9,13 @@
|
|||||||
|
|
||||||
#include <nlohmann/json_fwd.hpp>
|
#include <nlohmann/json_fwd.hpp>
|
||||||
|
|
||||||
|
struct SpooferConfig
|
||||||
|
{
|
||||||
|
bool spoofCharacterOwnership = false;
|
||||||
|
bool spoofInventory = false;
|
||||||
|
bool spoofCustomization = false;
|
||||||
|
};
|
||||||
|
|
||||||
class Spoofer
|
class Spoofer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -17,6 +24,7 @@ class Spoofer
|
|||||||
private:
|
private:
|
||||||
void registerListeners(Proxy* proxy);
|
void registerListeners(Proxy* proxy);
|
||||||
void loadData();
|
void loadData();
|
||||||
|
void loadConfig();
|
||||||
|
|
||||||
bool parseCatalog(std::string data);
|
bool parseCatalog(std::string data);
|
||||||
bool parseStackable(std::string data, std::unordered_set<std::string>& camperSet,
|
bool parseStackable(std::string data, std::unordered_set<std::string>& camperSet,
|
||||||
@@ -37,6 +45,8 @@ class Spoofer
|
|||||||
void serverResponseHandler(const std::string& url, std::string& body, std::string& respHeaders);
|
void serverResponseHandler(const std::string& url, std::string& body, std::string& respHeaders);
|
||||||
void clientRequestHandler(std::string& url, const std::string& body, std::string& reqHeaders);
|
void clientRequestHandler(std::string& url, const std::string& body, std::string& reqHeaders);
|
||||||
|
|
||||||
|
SpooferConfig _config;
|
||||||
|
|
||||||
std::unordered_set<std::string> _camperItemIds;
|
std::unordered_set<std::string> _camperItemIds;
|
||||||
std::unordered_set<std::string> _slasherPowerIds;
|
std::unordered_set<std::string> _slasherPowerIds;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user