diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..4120cad --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "CSSense/BluetoothLEController"] + path = CSSense/BluetoothLEController + url = git@github.com:Acurisu/BluetoothLEController.git +[submodule "CSSense/Gist"] + path = CSSense/Gist + url = https://gist.github.com/Acurisu/1805762f2c5e2ca6508c3c2dad4f3d6b diff --git a/CSSense.sln b/CSSense.sln new file mode 100644 index 0000000..089141e --- /dev/null +++ b/CSSense.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30711.63 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CSSense", "CSSense\CSSense.vcxproj", "{A6E48085-6124-4A7B-9F3B-CB58FE4676C4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A6E48085-6124-4A7B-9F3B-CB58FE4676C4}.Debug|x64.ActiveCfg = Debug|x64 + {A6E48085-6124-4A7B-9F3B-CB58FE4676C4}.Debug|x64.Build.0 = Debug|x64 + {A6E48085-6124-4A7B-9F3B-CB58FE4676C4}.Release|x64.ActiveCfg = Release|x64 + {A6E48085-6124-4A7B-9F3B-CB58FE4676C4}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1B4C55B9-B5BB-4534-A4C8-CE0E843001F0} + EndGlobalSection +EndGlobal diff --git a/CSSense/BluetoothLEController b/CSSense/BluetoothLEController new file mode 160000 index 0000000..53c6578 --- /dev/null +++ b/CSSense/BluetoothLEController @@ -0,0 +1 @@ +Subproject commit 53c6578221b405edb8113a13deb4be6342143910 diff --git a/CSSense/CSSense.cpp b/CSSense/CSSense.cpp new file mode 100644 index 0000000..0f9c1fe --- /dev/null +++ b/CSSense/CSSense.cpp @@ -0,0 +1,29 @@ +#include "pch.hpp" + +#include "GameStateIntegration.hpp" + +int main(int argc, char** argv) +{ + try + { + TCLAP::CmdLine cmd("CSSense CLI allows you to experience CSGO like never before", ' ', "0.1"); + + TCLAP::SwitchArg initSwitch("i", "init", "Initialize CSSense", cmd, false); + + cmd.parse(argc, argv); + + GameStateIntegration gSI(initSwitch.getValue()); + + gSI.open().wait(); + + std::cout << "Press ENTER to exit." << std::endl; + + std::string line; + std::getline(std::cin, line); + gSI.close().wait(); + } + catch (TCLAP::ArgException& e) + { + std::cerr << e.error() << " for arg " << e.argId() << std::endl; + } +} \ No newline at end of file diff --git a/CSSense/CSSense.vcxproj b/CSSense/CSSense.vcxproj new file mode 100644 index 0000000..b7bddce --- /dev/null +++ b/CSSense/CSSense.vcxproj @@ -0,0 +1,191 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {a6e48085-6124-4a7b-9f3b-cb58fe4676c4} + CSSense + 10.0.18362.0 + + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + Application + true + v142 + Unicode + + + Application + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + false + + + true + + + false + + + true + + + false + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + stdcpplatest + Use + pch.hpp + /await %(AdditionalOptions) + + + Console + true + WindowsApp.lib;bcrypt.lib;winhttp.lib;crypt32.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + stdcpplatest + Use + pch.hpp + /await %(AdditionalOptions) + MultiThreaded + true + + + Console + true + true + true + WindowsApp.lib;bcrypt.lib;winhttp.lib;crypt32.lib;%(AdditionalDependencies) + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + stdcpplatest + Use + pch.hpp + /await %(AdditionalOptions) + + + Console + true + WindowsApp.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + stdcpplatest + Use + pch.hpp + /await %(AdditionalOptions) + MultiThreaded + true + + + Console + true + true + true + WindowsApp.lib;%(AdditionalDependencies) + + + + + NotUsing + NotUsing + + + + + Create + Create + Create + Create + + + + + + + + + + + + + \ No newline at end of file diff --git a/CSSense/CSSense.vcxproj.filters b/CSSense/CSSense.vcxproj.filters new file mode 100644 index 0000000..901ee15 --- /dev/null +++ b/CSSense/CSSense.vcxproj.filters @@ -0,0 +1,48 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/CSSense/GameStateIntegration.cpp b/CSSense/GameStateIntegration.cpp new file mode 100644 index 0000000..58f42e6 --- /dev/null +++ b/CSSense/GameStateIntegration.cpp @@ -0,0 +1,619 @@ +#include "pch.hpp" + +#include "GameStateIntegration.hpp" + +void GameStateIntegration::sendVibrate(int strength) +{ + std::wstring cmd = L"Vibrate:" + std::to_wstring(strength) + L";"; + +#ifndef NO_BLE + if (!bLEController.GattWrite(cmd)) + { + std::cerr << "Failed sending a command to the device" << std::endl; + } +#endif + +#ifdef _DEBUG + std::wcout << DBG_START << L"Sent: " << cmd << DBG_END << std::endl; +#endif +} + +void GameStateIntegration::handleJSON(web::json::value msg) +{ + if (msg.has_object_field(L"previously") && msg.has_object_field(L"player")) + { + web::json::value player = msg.at(L"player"); + web::json::value previously = msg.at(L"previously"); + + if (previously.has_object_field(L"player")) + { + web::json::value previousPlayer = previously.at(L"player"); + + if (previously.has_boolean_field(L"map")) + { + if (previously.at(L"map").as_bool()) + { +#ifdef EVENTS + std::cout << EVT("Map unload") << std::endl; +#endif + + currentStrength = config.baseVibration; + isMVP = false; + isDead = false; + sendVibrate(config.baseVibration); + return; + } + } + + if (previously.has_object_field(L"round")) + { + web::json::value round = previously.at(L"round"); + if (round.has_string_field(L"phase") && round.at(L"phase").as_string() == L"over") + { +#ifdef EVENTS + std::cout << EVT("Round reset") << std::endl; +#endif + + currentStrength = config.baseVibration; + isMVP = false; + isDead = false; + sendVibrate(config.baseVibration); + return; + } + } + + if (isDead || (isMVP && config.burstOnMVP)) + { + return; + } + + if (previousPlayer.has_object_field(L"match_stats")) + { + web::json::value match_stats = previousPlayer.at(L"match_stats"); + if (config.burstOnMVP) + { + if (match_stats.has_integer_field(L"mvps")) + { +#ifdef EVENTS + std::cout << EVT("MVP") << std::endl; +#endif + + isMVP = true; + sendVibrate(20); + return; + } + } + + if (match_stats.has_integer_field(L"deaths")) + { +#ifdef EVENTS + std::cout << EVT("Dead") << std::endl; +#endif + + isDead = true; + currentStrength = config.baseVibration; + sendVibrate(config.baseVibration); + return; + } + } + + if (config.increaseOnKill) + { + if (previousPlayer.has_object_field(L"state") && player.has_object_field(L"state")) + { + web::json::value state = player.at(L"state"); + + if (previousPlayer.at(L"state").has_integer_field(L"round_kills") && state.has_integer_field(L"round_kills")) + { +#ifdef EVENTS + std::cout << EVT("Kill") << std::endl; +#endif + + web::json::value round_kills = state.at(L"round_kills"); + int strength = static_cast(config.baseVibration + round_kills.as_integer() * config.increaseAmount); + currentStrength = strength; + sendVibrate(std::clamp(strength, 0, 20)); + } + } + } + + if (config.stopOnKnife || config.vibrateOnShoot) + { + if (previousPlayer.has_object_field(L"weapons") && player.has_object_field(L"weapons")) + { + web::json::value previousWeapons = previousPlayer.at(L"weapons"); + web::json::object weapons = player.at(L"weapons").as_object(); + for (auto it = weapons.begin(); it != weapons.end(); ++it) + { + std::wstring name = it->first; + web::json::value weapon = it->second; + + if (weapon.has_string_field(L"state") && weapon.at(L"state").as_string() == L"active") + { + if (previousWeapons.has_object_field(name)) + { + web::json::value previousWeapon = previousWeapons.at(name); + + if (config.vibrateOnShoot) + { + if (previousWeapon.has_integer_field(L"ammo_clip") && weapon.has_integer_field(L"ammo_clip") && + !previousWeapon.has_string_field(L"name") && + previousWeapon.at(L"ammo_clip").as_integer() - 1 == weapon.at(L"ammo_clip").as_integer()) + { +#ifdef EVENTS + std::cout << EVT("Shot") << std::endl; +#endif + + lastShot = std::chrono::steady_clock::now(); + sendVibrate(currentStrength); + + pplx::wait(100); + + auto timeElapsed = std::chrono::duration_cast(std::chrono::steady_clock::now() - lastShot).count(); + if (timeElapsed > 100 && !isMVP && config.vibrateOnShoot) + { +#ifdef _DEBUG + std::cout << DBG("Reset") << std::endl; +#endif + + sendVibrate(config.baseVibration); + } + } + } + else if (config.stopOnKnife) + { + if (previousWeapon.has_string_field(L"state") && previousWeapon.at(L"state").as_string() == L"holstered") + { + if (weapon.has_string_field(L"type") && weapon.at(L"type").as_string() == L"Knife") + { +#ifdef EVENTS + std::cout << EVT("Knife active") << std::endl; +#endif + + sendVibrate(config.baseVibration); + return; + } +#ifdef EVENTS + std::cout << EVT("Knife holstered") << std::endl; +#endif + + sendVibrate(currentStrength); + } + } + } + } + } + } + } + } + } +} + +void GameStateIntegration::handlePost(http_request message) +{ +#ifdef _DEBUG + std::cout << DBG("Received post") << std::endl; +#endif + + message.reply(status_codes::OK); + + web::json::value msg = message.extract_json().get(); + + handleJSON(msg); +} + +void GameStateIntegration::setupListener(int port) +{ + mListener = http_listener(uri_builder(L"http://localhost:" + std::to_wstring(port)).to_string()); + mListener.support(methods::POST, std::bind(&GameStateIntegration::handlePost, this, std::placeholders::_1)); +} + +std::optional GameStateIntegration::getCSGOPath() +{ + winreg::RegKey key{ HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam" }; + if (std::optional steamPathO = key.TryGetStringValue(L"SteamPath")) + { + std::wstring steamPath = *steamPathO + std::wstring(L"/config/config.vdf"); // using steamapps/libraryfolders.vdf would be possible too + +#ifdef _DEBUG + std::wcout << DBG_START << L"Trying to open steam config at: " << steamPath << DBG_END << std::endl; +#endif + + std::ifstream steamConfig; + steamConfig.open(steamPath); + + if (steamConfig.good()) + { + std::regex baseInstallRegex("\"BaseInstallFolder_[0-9]+\"\t+\"(.+)\""); + + std::string line; + while (getline(steamConfig, line)) + { + std::smatch matches; + + if (std::regex_search(line, matches, baseInstallRegex)) + { +#ifdef _DEBUG + std::cout << DBG_START << "Found install folder at: " << matches[1] << DBG_END << std::endl; +#endif + + std::string csgoPath = std::string(matches[1]) + "\\\\steamapps\\\\common\\\\Counter-Strike Global Offensive\\\\csgo\\\\cfg"; + DWORD fileAttributes = GetFileAttributesA(csgoPath.c_str()); + + if (fileAttributes != INVALID_FILE_ATTRIBUTES && fileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + return csgoPath; + } + } + } + } + else + { +#ifdef _DEBUG + std::cout << DBG("Could not read config.vdf") << std::endl; +#endif + + return {}; + } + } + + return {}; +} + +int GameStateIntegration::createConfig() +{ + int port; + std::string input; + std::cout << "Enter the port to be used (default: 6969): "; + std::cin.clear(); + std::cin.sync(); + std::getline(std::cin, input); + + if (!input.empty()) + { + std::istringstream stream(input); + stream >> port; + + if (port == 0) + { + port = 6969; + } + + if (port < 1025) + { + std::cout << "You entered a well-known port. This potentially requires admin permissions." << std::endl; + } + } + else + { + port = 6969; + } + +#ifdef _DEBUG + std::cout << DBG_START << "Selected port is: " << port << DBG_END << std::endl; +#endif + + std::string csgoPath; + if (std::optional csgoPathO = getCSGOPath()) + { + csgoPath = *csgoPathO; + +#ifdef _DEBUG + std::cout << DBG_START << "Found CSGO directory at: " << csgoPath << DBG_END << std::endl; +#endif + + } + else + { + std::cout << "Could not determine CSGO's path automatically.\nPlease enter its installation location: "; + std::cin.clear(); + std::cin.sync(); + std::getline(std::cin, csgoPath); + + while (true) + { + csgoPath = std::regex_replace(csgoPath, std::regex("\\\\"), "\\\\"); + csgoPath += std::string("\\\\csgo\\\\cfg"); + DWORD fileAttributes = GetFileAttributesA(csgoPath.c_str()); + + if (fileAttributes != INVALID_FILE_ATTRIBUTES && fileAttributes & FILE_ATTRIBUTE_DIRECTORY) // fix + { + break; + } + + std::cerr << "The path you have entered is not valid\n"; + std::cout << "Please enter a valid csgo path: "; + std::cin.clear(); + std::cin.sync(); + std::getline(std::cin, csgoPath); + } + } + + std::string gameStateConfig(R"("CSSense" +{ + "uri" "http://localhost:)" + std::to_string(port) + R"(" + "timeout" "12.0" + "buffer" "0.0" + "throttle" "0.0" + "heartbeat" "120" + "output" + { + "precision_time" "3" + "precision_position" "1" + "precision_vector" "3" + } + "data" + { + "provider" "1" + "map" "1" + "round" "1" + "player_id" "1" + "player_state" "1" + "player_weapons" "1" + "player_match_stats" "1" + } +})"); + +#ifdef _DEBUG + std::cout << DBG_START << "Writing gamestate file to: " << csgoPath << DBG_END << std::endl; +#endif + + std::ofstream gameStateFile(csgoPath + "\\gamestate_integration_cssense.cfg"); + gameStateFile << gameStateConfig; + gameStateFile.close(); + + std::cout << "\nNow let's set up the config.\nEnter the minimum amount of strength the device should vibrate at at all times (0-20, integer) (default: 0): "; + std::cin.clear(); + std::cin.sync(); + std::getline(std::cin, input); + if (!input.empty()) + { + std::istringstream stream(input); + stream >> config.baseVibration; + + config.baseVibration = std::clamp(0, 20, config.baseVibration); + } + else + { + config.baseVibration = 0; + } + + std::cout << "Should the strength increase after a kill (T/F) (default: T)? "; + std::cin.clear(); + std::cin.sync(); + std::getline(std::cin, input); + if (!input.empty() && (input.starts_with('f') || input.starts_with('F'))) + { + config.increaseOnKill = false; + config.increaseAmount = 0; + config.vibrateOnShoot = false; + config.stopOnKnife = false; + } + else + { + config.increaseOnKill = true; + + std::cout << "Enter the amount by which the strength should get increased (or decreased) on kill (-20-20, double) (default: 3): "; + std::cin.clear(); + std::cin.sync(); + std::getline(std::cin, input); + if (!input.empty()) + { + std::istringstream stream(input); + stream >> config.increaseAmount; + config.increaseAmount = std::clamp(config.increaseAmount, -20., 20.); + } + else + { + config.increaseAmount = 3; + } + + std::cout << "Should the increased strength only get applied when shooting (T/F) (default: T)? "; + std::cin.clear(); + std::cin.sync(); + std::getline(std::cin, input); + if (!input.empty() && (input.starts_with('f') || input.starts_with('F'))) + { + config.vibrateOnShoot = false; + + std::cout << "Should the device return to base vibration when holding a knife (T/F) (default: T)? "; + std::cin.clear(); + std::cin.sync(); + std::getline(std::cin, input); + if (!input.empty() && (input.starts_with('f') || input.starts_with('F'))) + { + config.stopOnKnife = false; + } + else + { + config.stopOnKnife = true; + } + } + else + { + config.vibrateOnShoot = true; + config.stopOnKnife = false; + } + } + + std::cout << "Should the device vibrate at maximum strength on MVP (T/F) (default: T)? "; + std::cin.clear(); + std::cin.sync(); + std::getline(std::cin, input); + if (!input.empty() && (input.starts_with('f') || input.starts_with('F'))) + { + config.burstOnMVP = false; + } + else + { + config.burstOnMVP = true; + } + + std::ostringstream configStream; + configStream << std::boolalpha << "{\n\t\"baseVibration\": " << config.baseVibration << + ",\n\t\"increaseOnKill\": " << config.increaseOnKill << + ",\n\t\"increaseAmount\": " << config.increaseAmount << + ",\n\t\"vibrateOnShoot\": " << config.vibrateOnShoot << + ",\n\t\"stopOnKnife\": " << config.stopOnKnife << + ",\n\t\"burstOnMVP\": " << config.burstOnMVP << + ",\n\t\"gamestateConfigPath\": \"" << csgoPath << "\"\n}"; + +#ifdef _DEBUG + std::cout << DBG("Writing default config") << std::endl; + + std::cout << DBG_START << configStream.str() << DBG_END << std::endl; +#endif + + std::ofstream configFile("config.json"); + configFile << configStream.str(); + configFile.close(); + + std::cout << "\nEverything has been initialized.\n" + "You can configure the config to your liking by either editing 'config.json' or by running 'CSSense -i' again.\n" + "You can find an explanation on https://github.com/Acurisu/CSSense-CLI.\n" + "Restart CSGO if you had it running.\nEnjoy =^w^=\n" << std::endl; + + return port; +} + +int GameStateIntegration::parseConfig() +{ + std::ifstream configFile; + configFile.open("config.json"); + + if (configFile.good()) + { + std::stringstream buffer; + buffer << configFile.rdbuf(); + + try + { + web::json::value cfg = web::json::value::parse(buffer); + config.increaseOnKill = cfg.at(L"increaseOnKill").as_bool(); + config.vibrateOnShoot = cfg.at(L"vibrateOnShoot").as_bool(); + config.stopOnKnife = cfg.at(L"stopOnKnife").as_bool(); + config.burstOnMVP = cfg.at(L"burstOnMVP").as_bool(); + config.increaseAmount = cfg.at(L"increaseAmount").as_number().to_double(); + config.baseVibration = cfg.at(L"baseVibration").as_integer(); + + std::wstring gamestateConfigPath = cfg.at(L"gamestateConfigPath").as_string(); + +#ifdef _DEBUG + std::wcout << std::boolalpha << DBG_START << L"baseVibration:\t" << config.baseVibration + << L"\tincreaseOnKill:\t" << config.increaseOnKill + + << L"\n[DBG] increaseAmount:\t" << config.increaseAmount + << L"\tvibrateOnShoot:\t" << config.vibrateOnShoot + + << L"\n[DBG] stopOnKnife:\t" << config.stopOnKnife + << L"\tburstOnMVP:\t" << config.burstOnMVP + + << L"\n[DBG] gamestateConfigPath:\t" << gamestateConfigPath << DBG_END << std::endl; +#endif + + std::ifstream gamestateFile; + gamestateFile.open(gamestateConfigPath + L"\\gamestate_integration_cssense.cfg"); + + if (gamestateFile.good()) + { + std::regex portRegex("http:\\/\\/localhost:([0-9]+)"); + + std::string line; + while (std::getline(gamestateFile, line)) + { + std::smatch matches; + + if (std::regex_search(line, matches, portRegex)) + { +#ifdef _DEBUG + std::cout << DBG_START << "Found port: " << matches[1] << DBG_END << std::endl; +#endif + + return std::stoi(matches[1]); + } + } + } + else + { + std::cerr << "Something went wrong trying to retrieve the port.\n" + "Please run 'CSSense -i' again." << std::endl; + } + } + catch (web::json::json_exception e) + { + std::cerr << "Something went wrong trying to parse the config.\n" + "Please run 'CSSense -i' again or fix the error shown below:\n" + << e.what() << std::endl; + } + } + else + { + std::cerr << "Something went wrong trying to read the config.\nDid you forget to run 'CSSense -i'?" << std::endl; + } + + return -1; +} + +GameStateIntegration::GameStateIntegration(bool init) +{ + int port; + if (init) + { + port = createConfig(); + } + else + { + port = parseConfig(); + } + + if (port == -1) + { + exit(-1); + } + +#ifndef NO_BLE + std::wregex serviceGUIDRegex(L"^\\{..300001-002.-4bd4-bbd5-a6920e4c5653\\}"); + + std::cout << "Searching for a Lovesense device..." << std::endl; + + if (!bLEController.ConnectBLEDeviceByService(serviceGUIDRegex)) + { + std::cerr << "Could not connect to the BLE device" << std::endl; + exit(-1); + } + + if (!bLEController.SelectCharacteristics([]( + winrt::Windows::Devices::Bluetooth::GenericAttributeProfile:: + GattCharacteristic sender, + winrt::Windows::Devices::Bluetooth::GenericAttributeProfile:: + GattValueChangedEventArgs eventArgs) + { +#ifdef _DEBUG + std::cout << DBG_START << "Received: " << eventArgs.CharacteristicValue().data() << DBG_END << std::endl; +#endif + })) + { + std::cerr << "Could not select the specified characteristics" << std::endl; + exit(-1); + } + + std::cout << "Found and connected to the device." << std::endl; +#endif + + currentStrength = config.baseVibration; + sendVibrate(config.baseVibration); + setupListener(port); +} + +GameStateIntegration::~GameStateIntegration() +{ + sendVibrate(0); + +#ifndef NO_BLE + if (!bLEController.DisconnectBLEDevice()) + { + std::cerr << "Failed trying to disconnect the BLE device" << std::endl; + exit(-1); + } +#endif +} \ No newline at end of file diff --git a/CSSense/GameStateIntegration.hpp b/CSSense/GameStateIntegration.hpp new file mode 100644 index 0000000..cf3030e --- /dev/null +++ b/CSSense/GameStateIntegration.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "Macros.h" + +#ifdef _DEBUG +#define NO_BLE +#define EVENTS +#endif + +using namespace web; +using namespace http; +using namespace http::experimental::listener; + +struct Config +{ + int baseVibration; + bool increaseOnKill; + double increaseAmount; + bool vibrateOnShoot; + bool stopOnKnife; + bool burstOnMVP; +}; + +class GameStateIntegration +{ +private: + http_listener mListener; + Config config; + BluetoothLEController bLEController; + int currentStrength; + bool isMVP = false; + bool isDead = false; + std::chrono::steady_clock::time_point lastShot; + + void sendVibrate(int strength); + void handleJSON(web::json::value msg); + void handlePost(http_request message); + void setupListener(int port); + std::optional getCSGOPath(); + int createConfig(); + int parseConfig(); + +public: + GameStateIntegration(bool init); + ~GameStateIntegration(); + + pplx::task open() { return mListener.open(); } + pplx::task close() { return mListener.close(); } +}; + diff --git a/CSSense/Gist b/CSSense/Gist new file mode 160000 index 0000000..0d62d27 --- /dev/null +++ b/CSSense/Gist @@ -0,0 +1 @@ +Subproject commit 0d62d27fa1d1b3c84e7567d1e0b98a24cdfb4e59 diff --git a/CSSense/Macros.h b/CSSense/Macros.h new file mode 100644 index 0000000..fab34df --- /dev/null +++ b/CSSense/Macros.h @@ -0,0 +1,7 @@ +#pragma once + +#define DBG(txt) COLORIZE(FA_DEFAULT, FG_GRAY, BG_DEFAULT, "[DBG] " txt, RST_ALL) +#define DBG_START COLOR_START(FA_DEFAULT, FG_GRAY, BG_DEFAULT) "[DBG] " +#define DBG_END COLOR_END(RST_ALL) + +#define EVT(txt) COLORIZE(FA_DEFAULT, FG_SET24(42, 90, 90), BG_DEFAULT, "[EVT] " txt, RST_ALL) \ No newline at end of file diff --git a/CSSense/pch.cpp b/CSSense/pch.cpp new file mode 100644 index 0000000..3854579 --- /dev/null +++ b/CSSense/pch.cpp @@ -0,0 +1 @@ +#include "pch.hpp" diff --git a/CSSense/pch.hpp b/CSSense/pch.hpp new file mode 100644 index 0000000..33eef3e --- /dev/null +++ b/CSSense/pch.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include "BluetoothLEController/BluetoothLEController/BluetoothLEController.hpp" +#include "Gist/Color.h" \ No newline at end of file