#pragma once #include #include #include #include #include #include #include #define WS_ADDR "0.0.0.0" #define WS_PORT 4444 #define PLACEHOLDER_ITEM_ID "Anniversary2025Offering" class TinyMITMProxy; namespace ix { class WebSocket; class WebSocketServer; struct WebSocketMessage; class ConnectionState; } // namespace ix namespace seallib { class Logger; } struct SpooferConfig { std::unordered_map camperItems; std::unordered_map camperAddons; std::unordered_map slasherAddons; std::unordered_map camperOfferings; std::unordered_map slasherOfferings; std::unordered_map globalOfferings; std::unordered_set camperPerks; std::unordered_set slasherPerks; std::unordered_set catalogItemIds; std::unordered_set dlcListGRDK; std::unordered_set dlcListEGS; std::unordered_set dlcListSteam; std::unordered_set unlockedCharacters; }; namespace WSMessages { enum Action : int { INIT_CONFIG = 0, SYNC_STATE = 1, SYNC_TOGGLES = 2 }; struct Toggles { bool spoofItems = false; bool spoofPerks = false; bool spoofCatalog = false; bool spoofDLCs = false; }; struct Init { Action action = INIT_CONFIG; SpooferConfig profile; Toggles toggles; }; struct Request { Action action; SpooferConfig profile{}; Toggles toggles{}; }; } // namespace WSMessages class Spoofer { public: Spoofer(); ~Spoofer(); void registerListeners(TinyMITMProxy* proxy); private: /* local config handlers */ void loadConfig(); void saveConfig(); /* websocket server stuff */ void initServer(); void stopServer(); void wsMessageCallback(std::shared_ptr connectionState, ix::WebSocket& webSocket, const std::unique_ptr& msg); /* helpers */ void modifyCharacterInventory(glz::generic& js); void modifyCharacterData(glz::generic& js); void generateBloodweb(glz::generic& js); /* api handlers */ void onServerGetAll(std::string& body); void onServerInventoryAll(std::string& body); void onServerMessageList(std::string& body); void onServerBloodweb(std::string& body, std::string& respHeaders); void onServerUpdateEntitlements(const std::string& url, std::string& body); void onClientGetAll(std::string& body); void onClientBloodweb(std::string& body); void onClientUpdateEntitlements(const std::string& url, std::string& body); /* proxy handlers */ void serverResponseHandler(const std::string& url, std::string& body, std::string& headers, bool& blockOutgoing); void clientRequestHandler(const std::string& url, std::string& body, std::string& headers, bool wasBlocked); /* config */ bool _spoofItems = false; bool _spoofPerks = false; bool _spoofCatalog = false; bool _spoofDLCs = false; bool _spoofCharacters = false; std::unordered_map _camperItems; std::unordered_map _camperAddons; std::unordered_map _slasherAddons; std::unordered_map _camperOfferings; std::unordered_map _slasherOfferings; std::unordered_map _globalOfferings; std::unordered_set _camperPerks; std::unordered_set _slasherPerks; std::unordered_set _catalogItemIds; std::unordered_set _dlcListGRDK; std::unordered_set _dlcListEGS; std::unordered_set _dlcListSteam; std::unordered_set _unlockedCharacters; /* internal variables */ ix::WebSocketServer* _wsServer = nullptr; seallib::Logger* _log = nullptr; std::mutex _mutex; std::string _lastBwCharacter; };