From aa2ad156aa58d8646d2bc88040ecbf695eda4bfa Mon Sep 17 00:00:00 2001 From: mksudo Date: Sun, 18 Dec 2022 17:40:19 -0800 Subject: [PATCH] add settings for regenerate intervals and related gui --- .../src/user/cheat/imap/InteractiveMap.cpp | 287 ++++++++++++++++++ .../src/user/cheat/imap/InteractiveMap.h | 31 ++ 2 files changed, 318 insertions(+) diff --git a/cheat-library/src/user/cheat/imap/InteractiveMap.cpp b/cheat-library/src/user/cheat/imap/InteractiveMap.cpp index 9b255e87..2da51cd5 100644 --- a/cheat-library/src/user/cheat/imap/InteractiveMap.cpp +++ b/cheat-library/src/user/cheat/imap/InteractiveMap.cpp @@ -30,6 +30,7 @@ namespace cheat::feature NFS(f_STFixedPoints, "Fixed points", "InteractiveMap", SaveAttachType::Global), NFS(f_STCustomPoints, "Custom points", "InteractiveMap", SaveAttachType::Global), NFS(f_STCompletedPoints, "Save completed points", "InteractiveMap", SaveAttachType::Account), + NFS(f_STRegenerateIntervals, "Save regenerate intervals", "InteractiveMap", SaveAttachType::Global), NF(f_IconSize, "Icon size", "InteractiveMap", 20.0f), NF(f_MinimapIconSize, "Minimap icon size", "InteractiveMap", 14.0f), @@ -69,7 +70,9 @@ namespace cheat::feature CreateUserDataField("custom_points", f_CustomPointsJson, f_STCustomPoints.value()); CreateUserDataField("completed_points", f_CompletedPointsJson, f_STCompletedPoints.value()); CreateUserDataField("fixed_points", f_FixedPointsJson, f_STFixedPoints.value()); + CreateUserDataField("regenerate_intervals", f_RegenerateIntervalJson, f_STRegenerateIntervals.value()); + LoadCategoryRegenerateIntervals(); LoadCustomPoints(); LoadCompletedPoints(); LoadFixedPoints(); @@ -420,6 +423,8 @@ namespace cheat::feature } + DrawRegenerateIntervals(); + if (searchFixed) ImGui::EndChild(); } @@ -588,6 +593,37 @@ namespace cheat::feature ImGui::CloseCurrentPopup(); } + auto& sceneData = m_ScenesData[label.sceneID]; + auto& categories = sceneData.categories; + auto& categoryIntervals = sceneData.categoryIntervals; + + auto* currCategory = GetCategoryByLabelID(label.sceneID, label.id); + + if (currCategory != nullptr) + { + auto& currCategoryInterval = categoryIntervals[currCategory->name]; + + if (currCategoryInterval.labels.count(label.id) == 0) + { + currCategoryInterval.labels[label.id] = { + label.id, currCategoryInterval.interval, true + }; + } + + auto& currLabelInterval = currCategoryInterval.labels[label.id]; + + if ( + ImGui::InputInt("Set regenerate interval", &currLabelInterval.interval) + ) + { + if (currLabelInterval.interval < 0) currLabelInterval.interval = 0; + + currLabelInterval.followCategory = currLabelInterval.interval == currCategoryInterval.interval; + + SaveCategoryRegenerateIntervals(); + } + } + ImGui::EndPopup(); } // -- @@ -596,6 +632,84 @@ namespace cheat::feature return; } + void InteractiveMap::DrawRegenerateIntervals() + { + const auto sceneID = game::GetCurrentMapSceneID(); + if (m_ScenesData.count(sceneID) == 0) + ImGui::Text("Sorry. Current scene is not supported."); + + auto& sceneData = m_ScenesData[sceneID]; + auto& categories = sceneData.categories; + auto& categoryIntervals = sceneData.categoryIntervals; + auto& labels = sceneData.labels; + + for (auto& [categoryName, categoryLabels] : categories) + { + if (categoryIntervals.count(categoryName) == 0) + { + auto& categoryInterval = categoryIntervals[categoryName]; + + categoryInterval.name = categoryName; + categoryInterval.interval = 0; + } + + auto& categoryInterval = categoryIntervals[categoryName]; + + if ( + TypeWidget( + categoryName.c_str(), + categoryInterval.interval, + 1, 0, 7 * 24, + "Set regenerate interval for category" + ) + ) + { + if (categoryInterval.interval < 0) + categoryInterval.interval = 0; + + // no need to iterate over all children + // as all labels following category interval + // will not be saved + + SaveCategoryRegenerateIntervals(); + } + + if (categoryInterval.labels.size() == 0) + continue; + + for (auto& [labelID, labelRegenerateData] : categoryInterval.labels) + { + // only render special labels + if (labelRegenerateData.followCategory) + continue; + + auto& labelData = labels[labelID]; + + if ( + TypeWidget( + labelData.name.c_str(), + labelRegenerateData.interval, + 1, 0, 7 * 24, + "Set regenerate interval for material" + ) + ) + { + if (labelRegenerateData.interval < 0) + labelRegenerateData.interval = 0; + + if (labelRegenerateData.interval == categoryInterval.interval) + { + // label is not special anymore + // skip rendering in next frame + labelRegenerateData.followCategory = true; + } + + SaveCategoryRegenerateIntervals(); + } + } + } + } + InteractiveMap& InteractiveMap::GetInstance() { static InteractiveMap instance; @@ -1088,6 +1202,33 @@ namespace cheat::feature return; } + auto currentTimeStamp = util::GetCurrentTimeMillisec(); + auto completeTimestamp = data["complete_timestamp"].get(); + auto* category = GetCategoryByLabelID(labelData->sceneID, labelData->id); + + if (category == nullptr) return; + + auto& categoryRegenerateData = m_ScenesData[labelData->sceneID].categoryIntervals[category->name]; + + int64_t intervalInMS = 0; + + if (categoryRegenerateData.labels.count(labelData->id) == 0) + { + intervalInMS = categoryRegenerateData.interval * 60 * 60 * 1000; + } + else + { + auto& labelRegenerateData = categoryRegenerateData.labels[labelData->id]; + + intervalInMS = labelRegenerateData.interval * 60 * 60 * 1000; + } + + if (intervalInMS != 0 && completeTimestamp + intervalInMS <= currentTimeStamp) + { + // point regenerated, skipping setting point to completed + return; + } + point.completed = true; point.completeTimestamp = data["complete_timestamp"]; labelData->completedCount++; @@ -1207,6 +1348,134 @@ namespace cheat::feature m_CompletedPoints.clear(); } + void InteractiveMap::LoadCategoryRegenerateData(CategoryRegenerateInterval* categoryInterval, const nlohmann::json& data) + { + categoryInterval->name = data["name"]; + categoryInterval->interval = data["interval"].get(); + auto& labels = data["labels"]; + + for (auto& [labelIDStr, labelData] : labels.items()) + { + uint32_t labelID = std::stoul(labelIDStr); + int labelInterval = labelData.get(); + + categoryInterval->labels[labelID] = { + labelID, + labelInterval, + false, + }; + } + } + + void InteractiveMap::LoadCategoryRegenerateIntervals() + { + auto& regenerateIntervalContainer = f_RegenerateIntervalJson.value(); + + for (auto& [sceneID, sceneData] : m_ScenesData) + { + std::string sceneIDStr = std::to_string(sceneID); + + auto& categories = sceneData.categories; + auto& categoryIntervals = sceneData.categoryIntervals; + + if (regenerateIntervalContainer.count(sceneIDStr) == 0) + { + for (auto& category : categories) + { + categoryIntervals[category.name] = { + category.name, 0 + }; + } + } + else + { + auto& sceneRegenerateIntervalContainer = regenerateIntervalContainer[sceneIDStr]; + + for (auto& category : categories) + { + auto& categoryInterval = categoryIntervals[category.name]; + + if (sceneRegenerateIntervalContainer.count(category.name) == 0) + { + categoryInterval.name = category.name; + categoryInterval.interval = 0; + } + else + { + auto& categoryIntervalContainer = sceneRegenerateIntervalContainer[category.name]; + LoadCategoryRegenerateData(&categoryInterval, categoryIntervalContainer); + } + } + } + } + } + + void InteractiveMap::SaveCategoryRegenerateData(nlohmann::json& jObject, CategoryRegenerateInterval* categoryInterval) + { + jObject["name"] = categoryInterval->name; + jObject["interval"] = categoryInterval->interval; + + jObject["labels"] = nlohmann::json::object(); + auto& labelContainer = jObject["labels"]; + + for (auto& [labelID, labelRegenerateData] : categoryInterval->labels) + { + std::string labelIDStr = std::to_string(labelID); + // only save special labels + if (labelRegenerateData.followCategory) continue; + + labelContainer[labelIDStr] = labelRegenerateData.interval; + } + } + + void InteractiveMap::SaveCategoryRegenerateIntervals() + { + nlohmann::json regenerateIntervalContainer = {}; + + for (auto& [sceneID, sceneData] : m_ScenesData) + { + auto& categories = sceneData.categories; + auto& categoryIntervals = sceneData.categoryIntervals; + + std::string sceneIDStr = std::to_string(sceneID); + regenerateIntervalContainer[sceneIDStr] = nlohmann::json::object(); + auto& sceneRegenerateIntervalContainer = regenerateIntervalContainer[sceneIDStr]; + + for (auto& [categoryName, category] : categories) + { + sceneRegenerateIntervalContainer[categoryName] = nlohmann::json::object(); + auto& categoryIntervalContainer = sceneRegenerateIntervalContainer[categoryName]; + + auto& categoryRegenerateData = categoryIntervals[categoryName]; + SaveCategoryRegenerateData(categoryIntervalContainer, &categoryRegenerateData); + } + } + + f_RegenerateIntervalJson = regenerateIntervalContainer; + f_RegenerateIntervalJson.FireChanged(); + } + + void InteractiveMap::ResetCategoryRegenerateData(CategoryRegenerateInterval* categoryInterval) + { + categoryInterval->interval = 0; + categoryInterval->labels.clear(); + } + + void InteractiveMap::ResetCategoryRegenerateIntervals() + { + for (auto& [sceneID, sceneData] : m_ScenesData) + { + auto& categories = sceneData.categories; + auto& categoryIntervals = sceneData.categoryIntervals; + + for (auto& [categoryName, category] : categories) + { + auto& categoryRegenerateData = categoryIntervals[categoryName]; + ResetCategoryRegenerateData(&categoryRegenerateData); + } + } + } + void InteractiveMap::ReorderCompletedPointDataByTimestamp() { m_CompletedPoints.sort([](PointData* a, PointData* b) { return a->completeTimestamp < b->completeTimestamp; }); @@ -1979,6 +2248,24 @@ namespace cheat::feature return labels; } + InteractiveMap::CategoryData* InteractiveMap::GetCategoryByLabelID(uint32_t sceneID, uint32_t labelID) + { + auto& sceneData = m_ScenesData[sceneID]; + + for (auto& category : sceneData.categories) + { + for (auto& label : category.children) + { + if (label->id == labelID) + { + return &category; + } + } + } + + return nullptr; + } + void InteractiveMap::InitializeEntityFilter(game::IEntityFilter* filter, const std::string& clearName) { auto labels = FindLabelsByClearName(clearName); diff --git a/cheat-library/src/user/cheat/imap/InteractiveMap.h b/cheat-library/src/user/cheat/imap/InteractiveMap.h index 1751b513..2cd255a2 100644 --- a/cheat-library/src/user/cheat/imap/InteractiveMap.h +++ b/cheat-library/src/user/cheat/imap/InteractiveMap.h @@ -26,6 +26,7 @@ namespace cheat::feature config::Field> f_STFixedPoints; config::Field> f_STCustomPoints; config::Field> f_STCompletedPoints; + config::Field> f_STRegenerateIntervals; config::Field f_IconSize; config::Field f_MinimapIconSize; @@ -128,11 +129,26 @@ namespace cheat::feature std::vector children; }; + struct LabelRegenerateInterval + { + uint32_t id; + int interval; + bool followCategory; + }; + + struct CategoryRegenerateInterval + { + std::string name; + int interval; + std::map labels; + }; + struct SceneData { std::map labels; std::map nameToLabel; std::vector categories; + std::map categoryIntervals; }; struct MaterialData @@ -164,6 +180,9 @@ namespace cheat::feature config::Field f_CustomPointsJson; config::Field f_FixedPointsJson; config::Field f_CompletedPointsJson; + + // add config field for regenerate intervals + config::Field f_RegenerateIntervalJson; config::Field f_CustomPointIndex; // Stores last index for new custom points config::Field f_LastUserID; @@ -232,6 +251,14 @@ namespace cheat::feature void SaveFixedPoints(); void ResetFixedPoints(); + void LoadCategoryRegenerateData(CategoryRegenerateInterval* categoryInterval, const nlohmann::json& data); + void SaveCategoryRegenerateData(nlohmann::json& jObject, CategoryRegenerateInterval* categoryInterval); + void ResetCategoryRegenerateData(CategoryRegenerateInterval* categoryInterval); + + void LoadCategoryRegenerateIntervals(); + void SaveCategoryRegenerateIntervals(); + void ResetCategoryRegenerateIntervals(); + void CreateUserDataField(const char* name, config::Field& field, SaveAttachType saveType); void UpdateUserDataField(config::Field& field, SaveAttachType saveType, bool move = false); std::string GetUserDataFieldSection(SaveAttachType saveType); @@ -252,6 +279,8 @@ namespace cheat::feature void DrawPoints(); void DrawMinimapPoints(); + + void DrawRegenerateIntervals(); // Block interact void OnWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool& cancelled); @@ -265,6 +294,8 @@ namespace cheat::feature static PointData* FindNearestPoint(const LabelData& label, const app::Vector2& levelPosition, float range = 0.0f, bool completed = false); std::vector FindLabelsByClearName(const std::string& clearName); + CategoryData* GetCategoryByLabelID(uint32_t sceneID, uint32_t labelID); + // Hooks static void GadgetModule_OnGadgetInteractRsp_Hook(void* __this, app::GadgetInteractRsp* notify, MethodInfo* method); static void InLevelMapPageContext_UpdateView_Hook(app::InLevelMapPageContext* __this, MethodInfo* method);