diff --git a/EGameTools/source/ImGui/imguiex.cpp b/EGameTools/source/ImGui/imguiex.cpp index 3318649..500ad54 100644 --- a/EGameTools/source/ImGui/imguiex.cpp +++ b/EGameTools/source/ImGui/imguiex.cpp @@ -47,9 +47,17 @@ namespace ImGui { EndTabBar(); tabIndex = 1; } - bool Button(const char* label, const char* tooltip, const ImVec2& size_arg) { - bool btn = Button(label, size_arg); - SetItemTooltip(tooltip); + bool Button(const char* label, const char* tooltip, const ImVec2& size) { + bool btn = Button(label, size); + if (tooltip) + SetItemTooltip(tooltip); + return btn; + } + bool ButtonHotkey(const char* label, KeyBindOption* v, const char* tooltip, const ImVec2& size) { + bool btn = Button(label, size); + if (tooltip) + SetItemTooltip(tooltip); + Hotkey(std::string(label + std::string("##ToggleKey")), v); return btn; } bool Checkbox(const char* label, bool* v, const char* tooltip) { diff --git a/EGameTools/source/ImGui/imguiex.h b/EGameTools/source/ImGui/imguiex.h index 27892ef..c2c0a63 100644 --- a/EGameTools/source/ImGui/imguiex.h +++ b/EGameTools/source/ImGui/imguiex.h @@ -5,7 +5,8 @@ namespace ImGui { extern void StyleScaleAllSizes(ImGuiStyle* style, const float scale_factor, ImGuiStyle* defStyle = nullptr); extern void SpanNextTabAcrossWidth(const float width, const size_t tabs = 1); extern void EndTabBarEx(); - extern bool Button(const char* label, const char* tooltip, const ImVec2& size_arg = ImVec2(0, 0)); + extern bool Button(const char* label, const char* tooltip, const ImVec2& size = ImVec2(0, 0)); + extern bool ButtonHotkey(const char* label, KeyBindOption* v, const char* tooltip = nullptr, const ImVec2& size = ImVec2(0, 0)); extern bool Checkbox(const char* label, bool* v, const char* tooltip); extern bool Checkbox(const char* label, Option* v); extern bool Checkbox(const char* label, Option* v, const char* tooltip); diff --git a/EGameTools/source/config/config.cpp b/EGameTools/source/config/config.cpp index 991d2fe..9adffd7 100644 --- a/EGameTools/source/config/config.cpp +++ b/EGameTools/source/config/config.cpp @@ -12,8 +12,7 @@ namespace Config { enum ValueType { OPTION, Float, - String, - TPLocations + String }; struct VKey { @@ -4346,13 +4345,13 @@ namespace Config { { "Menu", "HasSeenChangelog", false, &Menu::hasSeenChangelog, OPTION }, { "Menu:Keybinds", "MenuToggleKey", std::string("VK_F5"), &Menu::menuToggle, String}, { "Menu:Keybinds", "GodModeToggleKey", std::string("VK_F6"), &Menu::Player::godMode, String}, - { "Menu:Keybinds", "FreezePlayerToggleKey", std::string("VK_F7"), &Menu::Player::freezePlayer, String }, + { "Menu:Keybinds", "FreezePlayerToggleKey", std::string("VK_NONE"), &Menu::Player::freezePlayer, String }, { "Menu:Keybinds", "UnlimitedImmunityToggleKey", std::string("VK_NONE"), &Menu::Player::unlimitedImmunity, String}, { "Menu:Keybinds", "UnlimitedStaminaToggleKey", std::string("VK_NONE"), &Menu::Player::unlimitedStamina, String}, { "Menu:Keybinds", "UnlimitedItemsToggleKey", std::string("VK_NONE"), &Menu::Player::unlimitedItems, String}, { "Menu:Keybinds", "OneHitKillToggleKey", std::string("VK_NONE"), &Menu::Player::oneHitKill, String}, { "Menu:Keybinds", "DisableOutOfBoundsTimerToggleKey", std::string("VK_NONE"), &Menu::Player::disableOutOfBoundsTimer, String}, - { "Menu:Keybinds", "NightrunnerModeToggleKey", std::string("VK_F9"), &Menu::Player::nightrunnerMode, String}, + { "Menu:Keybinds", "NightrunnerModeToggleKey", std::string("VK_F8"), &Menu::Player::nightrunnerMode, String}, { "Menu:Keybinds", "OneHandedModeToggleKey", std::string("VK_NONE"), &Menu::Player::oneHandedMode, String}, { "Menu:Keybinds", "AllowGrappleHookInSafezoneToggleKey", std::string("VK_NONE"), &Menu::Player::allowGrappleHookInSafezone, String}, { "Menu:Keybinds", "DisableAirControlToggleKey", std::string("VK_NONE"), &Menu::Player::disableAirControl, String }, @@ -4368,7 +4367,9 @@ namespace Config { { "Menu:Keybinds", "DisableSafezoneFOVReduction", std::string("VK_NONE"), &Menu::Camera::disableSafezoneFOVReduction, String }, { "Menu:Keybinds", "DisablePhotoModeLimits", std::string("VK_NONE"), &Menu::Camera::disablePhotoModeLimits, String}, { "Menu:Keybinds", "DisableHeadCorrectionToggleKey", std::string("VK_NONE"), &Menu::Camera::disableHeadCorrection, String }, - { "Menu:Keybinds", "DisableHUDToggleKey", std::string("VK_F8"), &Menu::Misc::disableHUD, String}, + { "Menu:Keybinds", "TeleportToSelectedLocationToggleKey", std::string("VK_F9"), &Menu::Teleport::teleportToSelectedLocation, String }, + { "Menu:Keybinds", "TeleportToCoordsToggleKey", std::string("VK_NONE"), &Menu::Teleport::teleportToCoords, String }, + { "Menu:Keybinds", "DisableHUDToggleKey", std::string("VK_F7"), &Menu::Misc::disableHUD, String}, { "Menu:Keybinds", "DisableGamePauseWhileAFKToggleKey", std::string("VK_NONE"), &Menu::Misc::disableGamePauseWhileAFK, String}, { "Menu:Keybinds", "FreezeTimeToggleKey", std::string("VK_NONE"), &Menu::World::freezeTime, String}, { "Menu:Keybinds", "SlowMotionToggleKey", std::string("VK_4"), &Menu::World::slowMotion, String}, @@ -4402,6 +4403,7 @@ namespace Config { { "Camera:Misc", "DisableSafezoneFOVReduction", true, &Menu::Camera::disableSafezoneFOVReduction, OPTION }, { "Camera:Misc", "DisablePhotoModeLimits", true, &Menu::Camera::disablePhotoModeLimits, OPTION }, { "Camera:Misc", "DisableHeadCorrection", false, &Menu::Camera::disableHeadCorrection, OPTION }, + { "Teleport:SavedLocations", "SavedTeleportLocations", std::string(""), &Menu::Teleport::savedTeleportLocations, String}, { "Misc:Misc", "DisableGamePauseWhileAFK", true, &Menu::Misc::disableGamePauseWhileAFK, OPTION }, { "Misc:GameChecks", "DisableSavegameCRCCheck", true, &Menu::Misc::disableSavegameCRCCheck, OPTION }, { "Misc:GameChecks", "DisableDataPAKsCRCCheck", true, &Menu::Misc::disableDataPAKsCRCCheck, OPTION }, @@ -4442,30 +4444,43 @@ namespace Config { const std::string loadSCRFilePath = desktopPathStr.empty() ? "" : desktopPathStr + "\\player_variables.scr"; + std::string strValue{}; for (auto entry : configVariablesDefault) { - if (entry.key == "LastSaveSCRPath") { - entry.value = desktopPathStr; - Menu::Player::saveSCRPath = desktopPathStr; - } - else if (entry.key == "LastLoadSCRFilePath") { - entry.value = loadSCRFilePath; - Menu::Player::loadSCRFilePath = loadSCRFilePath; - } - else if (entry.section == "Menu:Keybinds") { - const std::string toggleKey = std::any_cast(entry.value); - if (const auto it = std::ranges::find(virtualKeyCodes, toggleKey, &Config::VKey::name); it != virtualKeyCodes.end()) - reinterpret_cast(entry.optionPtr)->ChangeKeyBind(it->code); - } - switch (entry.type) { - case OPTION: + case OPTION: { + Option* option = reinterpret_cast(entry.optionPtr); + if (option->GetChangesAreDisabled()) + break; + option->SetBothValues(std::any_cast(entry.value)); reader.InsertEntry(entry.section.data(), entry.key.data(), std::any_cast(entry.value)); break; + } case Float: + *reinterpret_cast(entry.optionPtr) = std::any_cast(entry.value); reader.InsertEntry(entry.section.data(), entry.key.data(), std::any_cast(entry.value)); break; case String: - reader.InsertEntry(entry.section.data(), entry.key.data(), std::any_cast(entry.value)); + strValue = std::any_cast(entry.value); + + if (entry.key == "LastSaveSCRPath") { + entry.value = desktopPathStr; + Menu::Player::saveSCRPath = desktopPathStr; + } else if (entry.key == "LastLoadSCRFilePath") { + entry.value = loadSCRFilePath; + Menu::Player::loadSCRFilePath = loadSCRFilePath; + } else if (entry.section == "Menu:Keybinds") { + const std::string toggleKey = strValue; + if (const auto it = std::ranges::find(virtualKeyCodes, toggleKey, &Config::VKey::name); it != virtualKeyCodes.end()) + reinterpret_cast(entry.optionPtr)->ChangeKeyBind(it->code); + } else if (entry.key == "SavedTeleportLocations") { + Menu::Teleport::savedTeleportLocations = Menu::Teleport::ParseTeleportLocations(strValue); + Menu::Teleport::savedTeleportLocationNames.clear(); + for (const auto& tpLoc : Menu::Teleport::savedTeleportLocations) + Menu::Teleport::savedTeleportLocationNames.push_back(tpLoc.name.data()); + break; + } + + reader.InsertEntry(entry.section.data(), entry.key.data(), strValue); break; } } @@ -4516,8 +4531,7 @@ namespace Config { if (const auto it = std::ranges::find(virtualKeyCodes, strValue, &Config::VKey::name); it != virtualKeyCodes.end()) reinterpret_cast(entry.optionPtr)->ChangeKeyBind(it->code); break; - } - else if (entry.key == "LastSaveSCRPath") { + } else if (entry.key == "LastSaveSCRPath") { Menu::Player::saveSCRPath = strValue; if (Menu::Player::saveSCRPath.empty()) Menu::Player::saveSCRPath = desktopPathStr; @@ -4526,8 +4540,7 @@ namespace Config { if (!saveSCRPath.empty() && !(std::filesystem::is_directory(saveSCRPath.parent_path()) && std::filesystem::is_directory(saveSCRPath))) Menu::Player::saveSCRPath = {}; break; - } - else if (entry.key == "LastLoadSCRFilePath") { + } else if (entry.key == "LastLoadSCRFilePath") { Menu::Player::loadSCRFilePath = strValue; if (Menu::Player::loadSCRFilePath.empty()) Menu::Player::loadSCRFilePath = loadSCRFilePathStr; @@ -4536,6 +4549,12 @@ namespace Config { if (!loadSCRFilePath.empty() && !std::filesystem::is_directory(loadSCRFilePath.parent_path())) Menu::Player::loadSCRFilePath = {}; break; + } else if (entry.key == "SavedTeleportLocations") { + Menu::Teleport::savedTeleportLocations = Menu::Teleport::ParseTeleportLocations(strValue); + Menu::Teleport::savedTeleportLocationNames.clear(); + for (const auto& tpLoc : Menu::Teleport::savedTeleportLocations) + Menu::Teleport::savedTeleportLocationNames.push_back(tpLoc.name.data()); + break; } *reinterpret_cast(entry.optionPtr) = strValue; @@ -4579,6 +4598,11 @@ namespace Config { if (strValue != itMemVal->name) return true; break; + } else if (entry.key == "SavedTeleportLocations") { + std::string currentTPLocations = Menu::Teleport::ConvertTeleportLocationsToStr(Menu::Teleport::savedTeleportLocations); + if (strValue != currentTPLocations) + return true; + break; } if (strValue != *reinterpret_cast(entry.optionPtr)) @@ -4608,6 +4632,9 @@ namespace Config { if (const auto it = std::ranges::find(virtualKeyCodes, option->GetKeyBind(), &Config::VKey::code); it != virtualKeyCodes.end()) entry.value = std::string(it->name); break; + } else if (entry.key == "SavedTeleportLocations") { + entry.value = Menu::Teleport::ConvertTeleportLocationsToStr(Menu::Teleport::savedTeleportLocations); + break; } entry.value = *reinterpret_cast(entry.optionPtr); diff --git a/EGameTools/source/menu/misc.cpp b/EGameTools/source/menu/misc.cpp index b6d6615..973ef81 100644 --- a/EGameTools/source/menu/misc.cpp +++ b/EGameTools/source/menu/misc.cpp @@ -10,7 +10,7 @@ namespace GamePH::Hooks { namespace Menu { namespace Misc { KeyBindOption disableGamePauseWhileAFK{ VK_NONE }; - KeyBindOption disableHUD{ VK_F8 }; + KeyBindOption disableHUD{ VK_F7 }; Option disableSavegameCRCCheck{}; Option disableDataPAKsCRCCheck{}; Option increaseDataPAKsLimit{}; diff --git a/EGameTools/source/menu/player.cpp b/EGameTools/source/menu/player.cpp index 71a4575..e655a0a 100644 --- a/EGameTools/source/menu/player.cpp +++ b/EGameTools/source/menu/player.cpp @@ -6438,14 +6438,14 @@ namespace Menu { float playerMaxImmunity = 80.0f; int oldWorldMoney = 0; KeyBindOption godMode{ VK_F6 }; - KeyBindOption freezePlayer{ VK_F7 }; + KeyBindOption freezePlayer{ VK_NONE }; KeyBindOption unlimitedImmunity{ VK_NONE }; KeyBindOption unlimitedStamina{ VK_NONE }; KeyBindOption unlimitedItems{ VK_NONE }; KeyBindOption oneHitKill{ VK_NONE }; KeyBindOption invisibleToEnemies{ VK_NONE }; KeyBindOption disableOutOfBoundsTimer{ VK_NONE }; - KeyBindOption nightrunnerMode{ VK_F9 }; + KeyBindOption nightrunnerMode{ VK_F8 }; KeyBindOption oneHandedMode{ VK_NONE }; KeyBindOption allowGrappleHookInSafezone{ VK_NONE }; KeyBindOption disableAirControl{ VK_NONE }; diff --git a/EGameTools/source/menu/teleport.cpp b/EGameTools/source/menu/teleport.cpp index 7aabb2a..8847b66 100644 --- a/EGameTools/source/menu/teleport.cpp +++ b/EGameTools/source/menu/teleport.cpp @@ -9,11 +9,76 @@ namespace Menu { namespace Teleport { std::vector savedTeleportLocations; - static std::vector savedTeleportLocationNames; + std::vector savedTeleportLocationNames; static int selectedTPLocation = -1; static char newLocationName[25]{}; - static Vector3 teleportPos{}; + static Vector3 teleportCoords{}; + + KeyBindOption teleportToSelectedLocation{ VK_F9 }; + KeyBindOption teleportToCoords{ VK_NONE }; + + std::vector ParseTeleportLocations(const std::string& input) { + if (input.empty()) + return {}; + + std::vector teleportLocations{}; + std::stringstream ss(input); + std::string item{}; + + while (std::getline(ss, item, ';')) { + size_t colonPos = item.rfind(':'); + if (colonPos != std::string::npos) { + std::string tpLocName = item.substr(0, colonPos); + std::string tpLocCoords = item.substr(colonPos + 1); + + std::stringstream coordStream(tpLocCoords); + std::string coordItem{}; + std::vector coordValues{}; + while (std::getline(coordStream, coordItem, ',')) { + try { + coordValues.push_back(std::stof(coordItem)); + } catch (const std::invalid_argument& e) { + UNREFERENCED_PARAMETER(e); + spdlog::error("ParseTeleportLocations: Invalid coordinate value: {}, for location: {}", coordItem, tpLocName); + break; + } + } + + Vector3 tpLocPos{}; + if (coordValues.size() == 3) { + tpLocPos.X = coordValues[0]; + tpLocPos.Y = coordValues[1]; + tpLocPos.Z = coordValues[2]; + teleportLocations.push_back({ tpLocName, tpLocPos }); + } else + spdlog::error("ParseTeleportLocations: Invalid number of coordinates ({}) for location: {}", coordValues.size(), tpLocName); + } else + spdlog::error("ParseTeleportLocations: Invalid format for TP location: {}", item); + } + + spdlog::info("Successfully parsed teleport locations:"); + int tpLocIndex = 1; + for (const auto& loc : teleportLocations) { + spdlog::info("{}. \"{}\" (X: {}, Y: {}, Z: {})", tpLocIndex, loc.name, loc.pos.X, loc.pos.Y, loc.pos.Z); + tpLocIndex++; + } + + return teleportLocations; + } + std::string ConvertTeleportLocationsToStr(const std::vector& teleportLocations) { + std::stringstream ss{}; + + for (size_t i = 0; i < teleportLocations.size(); ++i) { + const TeleportLocation& loc = teleportLocations[i]; + + ss << loc.name << ":" << loc.pos.X << "," << loc.pos.Y << "," << loc.pos.Z; + if (i < teleportLocations.size() - 1) + ss << ";"; + } + + return ss.str(); + } static bool isTeleportationDisabled() { GamePH::LevelDI* iLevel = GamePH::LevelDI::Get(); @@ -41,13 +106,13 @@ namespace Menu { if (camPos.isDefault()) return; - teleportPos = camPos; + teleportCoords = camPos; } else { Engine::CBulletPhysicsCharacter* playerCharacter = Engine::CBulletPhysicsCharacter::Get(); if (!playerCharacter) return; - teleportPos = playerCharacter->playerPos; + teleportCoords = playerCharacter->playerPos; } } static void TeleportPlayerTo(const Vector3& pos) { @@ -82,11 +147,11 @@ namespace Menu { } static void UpdateTeleportPos() { if (isTeleportationDisabled()) { - if (!teleportPos.isDefault()) - teleportPos = Vector3(); + if (!teleportCoords.isDefault()) + teleportCoords = Vector3(); return; } - if (!teleportPos.isDefault()) + if (!teleportCoords.isDefault()) return; if (Camera::freeCam.GetValue()) { @@ -99,13 +164,26 @@ namespace Menu { if (camPos.isDefault()) return; - teleportPos = camPos; + teleportCoords = camPos; } else { Engine::CBulletPhysicsCharacter* playerCharacter = Engine::CBulletPhysicsCharacter::Get(); if (!playerCharacter) return; - teleportPos = playerCharacter->playerPos; + teleportCoords = playerCharacter->playerPos; + } + } + static void HotkeysUpdate() { + teleportToSelectedLocation.SetChangesAreDisabled(selectedTPLocation < 0 || selectedTPLocation >= savedTeleportLocations.size()); + teleportToCoords.SetChangesAreDisabled(isTeleportationDisabled()); + + if (teleportToSelectedLocation.HasChanged()) { + TeleportPlayerTo(savedTeleportLocations[selectedTPLocation].pos); + teleportToSelectedLocation.SetPrevValue(teleportToSelectedLocation.GetValue()); + } + if (teleportToCoords.HasChanged()) { + TeleportPlayerTo(teleportCoords); + teleportToCoords.SetPrevValue(teleportToCoords.GetValue()); } } @@ -159,12 +237,13 @@ namespace Menu { TeleportLocation tpLocation = TeleportLocation(locationName, playerPos); savedTeleportLocations.push_back(tpLocation); - savedTeleportLocationNames.push_back(locationName); + savedTeleportLocationNames.push_back(tpLocation.name.data()); } static void HandleDialogs() { if (ImGui::BeginPopupModal("Give the location a name", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { if (ImGui::InputTextWithHint("##TPLocationNameInputText", "Location name", newLocationName, IM_ARRAYSIZE(newLocationName), ImGuiInputTextFlags_EnterReturnsTrue) || ImGui::Button("OK", ImVec2(120.0f, 0.0f))) { SaveTeleportLocation(newLocationName); + newLocationName[0] = 0; ImGui::CloseCurrentPopup(); } ImGui::EndPopup(); @@ -186,6 +265,7 @@ namespace Menu { Tab Tab::instance{}; void Tab::Update() { UpdateTeleportPos(); + HotkeysUpdate(); } void Tab::Render() { ImGui::SeparatorText("Saved Locations##Teleport"); @@ -194,17 +274,21 @@ namespace Menu { ImGui::ListBox("##SavedTPLocationsListBox", &selectedTPLocation, savedTeleportLocationNames.data(), static_cast(savedTeleportLocationNames.size()), 5); ImGui::PopItemWidth(); - ImGui::BeginDisabled(selectedTPLocation < 0 || selectedTPLocation >= savedTeleportLocations.size()); { - if (ImGui::Button("Teleport to Selected Location")) - TeleportPlayerTo(savedTeleportLocations[selectedTPLocation].pos); - ImGui::SameLine(); - if (ImGui::Button("Remove Selected Location")) { - savedTeleportLocations.erase(savedTeleportLocations.begin() + selectedTPLocation); - savedTeleportLocationNames.erase(savedTeleportLocationNames.begin() + selectedTPLocation); - selectedTPLocation = -1; - } - ImGui::EndDisabled(); + ImGui::EndDisabled(); + } + + ImGui::BeginDisabled(isTeleportationDisabled() || selectedTPLocation < 0 || selectedTPLocation >= savedTeleportLocations.size()); { + if (ImGui::ButtonHotkey("Teleport to Selected Location", &teleportToSelectedLocation, "Teleports player to selected location from the saved locations list")) + TeleportPlayerTo(savedTeleportLocations[selectedTPLocation].pos); + ImGui::SameLine(); + if (ImGui::Button("Remove Selected Location")) { + savedTeleportLocations.erase(savedTeleportLocations.begin() + selectedTPLocation); + savedTeleportLocationNames.erase(savedTeleportLocationNames.begin() + selectedTPLocation); + selectedTPLocation = -1; } + ImGui::EndDisabled(); + } + ImGui::BeginDisabled(isTeleportationDisabled()); { ImGui::SameLine(); if (ImGui::Button("Save Current Location")) ImGui::OpenPopup("Give the location a name"); @@ -239,15 +323,15 @@ namespace Menu { ImGui::Text(cameraPos.data()); ImGui::PushItemWidth(200.0f); - ImGui::InputFloat("X", &teleportPos.X, 1.0f, 10.0f, "%.3f"); + ImGui::InputFloat("X", &teleportCoords.X, 1.0f, 10.0f, "%.3f"); ImGui::SameLine(); - ImGui::InputFloat("Y", &teleportPos.Y, 1.0f, 10.0f, "%.3f"); + ImGui::InputFloat("Y", &teleportCoords.Y, 1.0f, 10.0f, "%.3f"); ImGui::SameLine(); - ImGui::InputFloat("Z", &teleportPos.Z, 1.0f, 10.0f, "%.3f"); + ImGui::InputFloat("Z", &teleportCoords.Z, 1.0f, 10.0f, "%.3f"); ImGui::PopItemWidth(); - if (ImGui::Button("Teleport to Coords")) - TeleportPlayerTo(teleportPos); + if (ImGui::ButtonHotkey("Teleport to Coords", &teleportToCoords, "Teleports player to the coords specified in the input boxes above")) + TeleportPlayerTo(teleportCoords); ImGui::SameLine(); if (ImGui::Button("Get Player Coords")) SyncTPCoordsToPlayer(); diff --git a/EGameTools/source/menu/teleport.h b/EGameTools/source/menu/teleport.h index d00c936..4dae9dd 100644 --- a/EGameTools/source/menu/teleport.h +++ b/EGameTools/source/menu/teleport.h @@ -9,6 +9,13 @@ namespace Menu { }; extern std::vector savedTeleportLocations; + extern std::vector savedTeleportLocationNames; + + extern KeyBindOption teleportToSelectedLocation; + extern KeyBindOption teleportToCoords; + + extern std::vector ParseTeleportLocations(const std::string& input); + extern std::string ConvertTeleportLocationsToStr(const std::vector& teleportLocations); class Tab : MenuTab { public: