diff options
Diffstat (limited to 'src/ap_state.cpp')
| -rw-r--r-- | src/ap_state.cpp | 89 |
1 files changed, 44 insertions, 45 deletions
| diff --git a/src/ap_state.cpp b/src/ap_state.cpp index 1e5621d..8438649 100644 --- a/src/ap_state.cpp +++ b/src/ap_state.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <any> | 10 | #include <any> |
| 11 | #include <apclient.hpp> | 11 | #include <apclient.hpp> |
| 12 | #include <apuuid.hpp> | 12 | #include <apuuid.hpp> |
| 13 | #include <bitset> | ||
| 13 | #include <chrono> | 14 | #include <chrono> |
| 14 | #include <exception> | 15 | #include <exception> |
| 15 | #include <filesystem> | 16 | #include <filesystem> |
| @@ -28,8 +29,8 @@ | |||
| 28 | #include "tracker_state.h" | 29 | #include "tracker_state.h" |
| 29 | 30 | ||
| 30 | constexpr int AP_MAJOR = 0; | 31 | constexpr int AP_MAJOR = 0; |
| 31 | constexpr int AP_MINOR = 4; | 32 | constexpr int AP_MINOR = 6; |
| 32 | constexpr int AP_REVISION = 5; | 33 | constexpr int AP_REVISION = 1; |
| 33 | 34 | ||
| 34 | constexpr const char* CERT_STORE_PATH = "cacert.pem"; | 35 | constexpr const char* CERT_STORE_PATH = "cacert.pem"; |
| 35 | constexpr int ITEM_HANDLING = 7; // <- all | 36 | constexpr int ITEM_HANDLING = 7; // <- all |
| @@ -37,6 +38,10 @@ constexpr int ITEM_HANDLING = 7; // <- all | |||
| 37 | constexpr int CONNECTION_TIMEOUT = 50000; // 50 seconds | 38 | constexpr int CONNECTION_TIMEOUT = 50000; // 50 seconds |
| 38 | constexpr int CONNECTION_BACKOFF_INTERVAL = 100; | 39 | constexpr int CONNECTION_BACKOFF_INTERVAL = 100; |
| 39 | 40 | ||
| 41 | constexpr int PANEL_COUNT = 803; | ||
| 42 | constexpr int PANEL_BITFIELD_LENGTH = 48; | ||
| 43 | constexpr int PANEL_BITFIELDS = 17; | ||
| 44 | |||
| 40 | namespace { | 45 | namespace { |
| 41 | 46 | ||
| 42 | const std::set<long> kNonProgressionItems = { | 47 | const std::set<long> kNonProgressionItems = { |
| @@ -79,6 +84,7 @@ struct APState { | |||
| 79 | std::set<int64_t> checked_locations; | 84 | std::set<int64_t> checked_locations; |
| 80 | std::map<std::string, std::any> data_storage; | 85 | std::map<std::string, std::any> data_storage; |
| 81 | std::optional<std::tuple<int, int>> player_pos; | 86 | std::optional<std::tuple<int, int>> player_pos; |
| 87 | std::bitset<PANEL_COUNT> solved_panels; | ||
| 82 | 88 | ||
| 83 | DoorShuffleMode door_shuffle_mode = kNO_DOORS; | 89 | DoorShuffleMode door_shuffle_mode = kNO_DOORS; |
| 84 | bool group_doors = false; | 90 | bool group_doors = false; |
| @@ -142,6 +148,7 @@ struct APState { | |||
| 142 | checked_locations.clear(); | 148 | checked_locations.clear(); |
| 143 | data_storage.clear(); | 149 | data_storage.clear(); |
| 144 | player_pos = std::nullopt; | 150 | player_pos = std::nullopt; |
| 151 | solved_panels.reset(); | ||
| 145 | victory_data_storage_key.clear(); | 152 | victory_data_storage_key.clear(); |
| 146 | door_shuffle_mode = kNO_DOORS; | 153 | door_shuffle_mode = kNO_DOORS; |
| 147 | group_doors = false; | 154 | group_doors = false; |
| @@ -216,24 +223,13 @@ struct APState { | |||
| 216 | return checked_locations.count(location_id); | 223 | return checked_locations.count(location_id); |
| 217 | } | 224 | } |
| 218 | 225 | ||
| 219 | bool HasCheckedHuntPanel(int location_id) { | ||
| 220 | std::lock_guard state_guard(state_mutex); | ||
| 221 | |||
| 222 | std::string key = | ||
| 223 | fmt::format("{}Hunt|{}", data_storage_prefix, location_id); | ||
| 224 | return data_storage.count(key) && std::any_cast<bool>(data_storage.at(key)); | ||
| 225 | } | ||
| 226 | |||
| 227 | bool HasItem(int item_id, int quantity) { | 226 | bool HasItem(int item_id, int quantity) { |
| 228 | return inventory.count(item_id) && inventory.at(item_id) >= quantity; | 227 | return inventory.count(item_id) && inventory.at(item_id) >= quantity; |
| 229 | } | 228 | } |
| 230 | 229 | ||
| 231 | bool HasAchievement(const std::string& name) { | 230 | bool HasItemSafe(int item_id, int quantity) { |
| 232 | std::lock_guard state_guard(state_mutex); | 231 | std::lock_guard state_guard(state_mutex); |
| 233 | 232 | return HasItem(item_id, quantity); | |
| 234 | std::string key = | ||
| 235 | fmt::format("{}Achievement|{}", data_storage_prefix, name); | ||
| 236 | return data_storage.count(key) && std::any_cast<bool>(data_storage.at(key)); | ||
| 237 | } | 233 | } |
| 238 | 234 | ||
| 239 | const std::set<std::string>& GetCheckedPaintings() { | 235 | const std::set<std::string>& GetCheckedPaintings() { |
| @@ -257,8 +253,6 @@ struct APState { | |||
| 257 | checked_paintings.count(painting_mapping.at(painting_id))); | 253 | checked_paintings.count(painting_mapping.at(painting_id))); |
| 258 | } | 254 | } |
| 259 | 255 | ||
| 260 | std::string GetItemName(int id) { return apclient->get_item_name(id, "Lingo"); } | ||
| 261 | |||
| 262 | void RevealPaintings() { | 256 | void RevealPaintings() { |
| 263 | std::lock_guard state_guard(state_mutex); | 257 | std::lock_guard state_guard(state_mutex); |
| 264 | 258 | ||
| @@ -283,6 +277,12 @@ struct APState { | |||
| 283 | 30; // CLIENT_GOAL | 277 | 30; // CLIENT_GOAL |
| 284 | } | 278 | } |
| 285 | 279 | ||
| 280 | bool IsPanelSolved(int solve_index) { | ||
| 281 | std::lock_guard state_guard(state_mutex); | ||
| 282 | |||
| 283 | return solved_panels.test(solve_index); | ||
| 284 | } | ||
| 285 | |||
| 286 | private: | 286 | private: |
| 287 | void Initialize() { | 287 | void Initialize() { |
| 288 | if (!initialized) { | 288 | if (!initialized) { |
| @@ -290,16 +290,8 @@ struct APState { | |||
| 290 | 290 | ||
| 291 | std::thread([this]() { Thread(); }).detach(); | 291 | std::thread([this]() { Thread(); }).detach(); |
| 292 | 292 | ||
| 293 | for (int panel_id : GD_GetAchievementPanels()) { | 293 | for (int i = 0; i < PANEL_BITFIELDS; i++) { |
| 294 | tracked_data_storage_keys.push_back(fmt::format( | 294 | tracked_data_storage_keys.push_back(fmt::format("Panels_{}", i)); |
| 295 | "Achievement|{}", GD_GetPanel(panel_id).achievement_name)); | ||
| 296 | } | ||
| 297 | |||
| 298 | for (const MapArea& map_area : GD_GetMapAreas()) { | ||
| 299 | for (const Location& location : map_area.locations) { | ||
| 300 | tracked_data_storage_keys.push_back( | ||
| 301 | fmt::format("Hunt|{}", location.ap_location_id)); | ||
| 302 | } | ||
| 303 | } | 295 | } |
| 304 | 296 | ||
| 305 | tracked_data_storage_keys.push_back("PlayerPos"); | 297 | tracked_data_storage_keys.push_back("PlayerPos"); |
| @@ -425,7 +417,7 @@ struct APState { | |||
| 425 | } | 417 | } |
| 426 | 418 | ||
| 427 | for (const auto& [item_id, item_index] : index_by_item) { | 419 | for (const auto& [item_id, item_index] : index_by_item) { |
| 428 | item_states.push_back(ItemState{.name = GetItemName(item_id), | 420 | item_states.push_back(ItemState{.name = GD_GetItemName(item_id), |
| 429 | .amount = inventory[item_id], | 421 | .amount = inventory[item_id], |
| 430 | .index = item_index}); | 422 | .index = item_index}); |
| 431 | } | 423 | } |
| @@ -511,8 +503,9 @@ struct APState { | |||
| 511 | : kSUNWARP_ACCESS_NORMAL; | 503 | : kSUNWARP_ACCESS_NORMAL; |
| 512 | sunwarp_shuffle = slot_data.contains("shuffle_sunwarps") && | 504 | sunwarp_shuffle = slot_data.contains("shuffle_sunwarps") && |
| 513 | slot_data["shuffle_sunwarps"].get<int>() == 1; | 505 | slot_data["shuffle_sunwarps"].get<int>() == 1; |
| 514 | postgame_shuffle = slot_data.contains("shuffle_postgame") && | 506 | postgame_shuffle = slot_data.contains("shuffle_postgame") |
| 515 | slot_data["shuffle_postgame"].get<int>() == 1; | 507 | ? (slot_data["shuffle_postgame"].get<int>() == 1) |
| 508 | : true; | ||
| 516 | 509 | ||
| 517 | if (painting_shuffle && slot_data.contains("painting_entrance_to_exit")) { | 510 | if (painting_shuffle && slot_data.contains("painting_entrance_to_exit")) { |
| 518 | painting_mapping.clear(); | 511 | painting_mapping.clear(); |
| @@ -603,11 +596,6 @@ struct APState { | |||
| 603 | TrackerLog(fmt::format("Data storage {} retrieved as {}", key, | 596 | TrackerLog(fmt::format("Data storage {} retrieved as {}", key, |
| 604 | (value.get<bool>() ? "true" : "false"))); | 597 | (value.get<bool>() ? "true" : "false"))); |
| 605 | 598 | ||
| 606 | if (key.find("Achievement|") != std::string::npos) { | ||
| 607 | state_update.achievements = true; | ||
| 608 | } else if (key.find("Hunt|") != std::string::npos) { | ||
| 609 | state_update.hunt_panels = true; | ||
| 610 | } | ||
| 611 | } else if (value.is_number()) { | 599 | } else if (value.is_number()) { |
| 612 | data_storage[key] = value.get<int>(); | 600 | data_storage[key] = value.get<int>(); |
| 613 | TrackerLog(fmt::format("Data storage {} retrieved as {}", key, | 601 | TrackerLog(fmt::format("Data storage {} retrieved as {}", key, |
| @@ -615,6 +603,21 @@ struct APState { | |||
| 615 | 603 | ||
| 616 | if (key == victory_data_storage_key) { | 604 | if (key == victory_data_storage_key) { |
| 617 | state_update.cleared_locations = true; | 605 | state_update.cleared_locations = true; |
| 606 | } else if (key.find("Panels_") != std::string::npos) { | ||
| 607 | int bitfield_num = | ||
| 608 | std::stoi(key.substr(data_storage_prefix.size() + 7)); | ||
| 609 | uint64_t bitfield_value = value.get<uint64_t>(); | ||
| 610 | for (int i = 0; i < PANEL_BITFIELD_LENGTH; i++) { | ||
| 611 | if ((bitfield_value & (1LL << i)) != 0) { | ||
| 612 | int solve_index = bitfield_num * PANEL_BITFIELD_LENGTH + i; | ||
| 613 | |||
| 614 | if (!solved_panels.test(solve_index)) { | ||
| 615 | state_update.panels.insert(solve_index); | ||
| 616 | } | ||
| 617 | |||
| 618 | solved_panels.set(solve_index); | ||
| 619 | } | ||
| 620 | } | ||
| 618 | } | 621 | } |
| 619 | } else if (value.is_object()) { | 622 | } else if (value.is_object()) { |
| 620 | if (key.ends_with("PlayerPos")) { | 623 | if (key.ends_with("PlayerPos")) { |
| @@ -715,16 +718,12 @@ bool AP_HasCheckedGameLocation(int location_id) { | |||
| 715 | return GetState().HasCheckedGameLocation(location_id); | 718 | return GetState().HasCheckedGameLocation(location_id); |
| 716 | } | 719 | } |
| 717 | 720 | ||
| 718 | bool AP_HasCheckedHuntPanel(int location_id) { | ||
| 719 | return GetState().HasCheckedHuntPanel(location_id); | ||
| 720 | } | ||
| 721 | |||
| 722 | bool AP_HasItem(int item_id, int quantity) { | 721 | bool AP_HasItem(int item_id, int quantity) { |
| 723 | return GetState().HasItem(item_id, quantity); | 722 | return GetState().HasItem(item_id, quantity); |
| 724 | } | 723 | } |
| 725 | 724 | ||
| 726 | std::string AP_GetItemName(int item_id) { | 725 | bool AP_HasItemSafe(int item_id, int quantity) { |
| 727 | return GetState().GetItemName(item_id); | 726 | return GetState().HasItemSafe(item_id, quantity); |
| 728 | } | 727 | } |
| 729 | 728 | ||
| 730 | DoorShuffleMode AP_GetDoorShuffleMode() { | 729 | DoorShuffleMode AP_GetDoorShuffleMode() { |
| @@ -830,10 +829,6 @@ VictoryCondition AP_GetVictoryCondition() { | |||
| 830 | return GetState().victory_condition; | 829 | return GetState().victory_condition; |
| 831 | } | 830 | } |
| 832 | 831 | ||
| 833 | bool AP_HasAchievement(const std::string& achievement_name) { | ||
| 834 | return GetState().HasAchievement(achievement_name); | ||
| 835 | } | ||
| 836 | |||
| 837 | bool AP_HasEarlyColorHallways() { | 832 | bool AP_HasEarlyColorHallways() { |
| 838 | std::lock_guard state_guard(GetState().state_mutex); | 833 | std::lock_guard state_guard(GetState().state_mutex); |
| 839 | 834 | ||
| @@ -883,3 +878,7 @@ std::optional<std::tuple<int, int>> AP_GetPlayerPosition() { | |||
| 883 | 878 | ||
| 884 | return GetState().player_pos; | 879 | return GetState().player_pos; |
| 885 | } | 880 | } |
| 881 | |||
| 882 | bool AP_IsPanelSolved(int solve_index) { | ||
| 883 | return GetState().IsPanelSolved(solve_index); | ||
| 884 | } | ||
