about summary refs log tree commit diff stats
path: root/src/ap_state.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ap_state.cpp')
-rw-r--r--src/ap_state.cpp89
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
30constexpr int AP_MAJOR = 0; 31constexpr int AP_MAJOR = 0;
31constexpr int AP_MINOR = 4; 32constexpr int AP_MINOR = 6;
32constexpr int AP_REVISION = 5; 33constexpr int AP_REVISION = 1;
33 34
34constexpr const char* CERT_STORE_PATH = "cacert.pem"; 35constexpr const char* CERT_STORE_PATH = "cacert.pem";
35constexpr int ITEM_HANDLING = 7; // <- all 36constexpr int ITEM_HANDLING = 7; // <- all
@@ -37,6 +38,10 @@ constexpr int ITEM_HANDLING = 7; // <- all
37constexpr int CONNECTION_TIMEOUT = 50000; // 50 seconds 38constexpr int CONNECTION_TIMEOUT = 50000; // 50 seconds
38constexpr int CONNECTION_BACKOFF_INTERVAL = 100; 39constexpr int CONNECTION_BACKOFF_INTERVAL = 100;
39 40
41constexpr int PANEL_COUNT = 803;
42constexpr int PANEL_BITFIELD_LENGTH = 48;
43constexpr int PANEL_BITFIELDS = 17;
44
40namespace { 45namespace {
41 46
42const std::set<long> kNonProgressionItems = { 47const 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
718bool AP_HasCheckedHuntPanel(int location_id) {
719 return GetState().HasCheckedHuntPanel(location_id);
720}
721
722bool AP_HasItem(int item_id, int quantity) { 721bool 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
726std::string AP_GetItemName(int item_id) { 725bool AP_HasItemSafe(int item_id, int quantity) {
727 return GetState().GetItemName(item_id); 726 return GetState().HasItemSafe(item_id, quantity);
728} 727}
729 728
730DoorShuffleMode AP_GetDoorShuffleMode() { 729DoorShuffleMode AP_GetDoorShuffleMode() {
@@ -830,10 +829,6 @@ VictoryCondition AP_GetVictoryCondition() {
830 return GetState().victory_condition; 829 return GetState().victory_condition;
831} 830}
832 831
833bool AP_HasAchievement(const std::string& achievement_name) {
834 return GetState().HasAchievement(achievement_name);
835}
836
837bool AP_HasEarlyColorHallways() { 832bool 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
882bool AP_IsPanelSolved(int solve_index) {
883 return GetState().IsPanelSolved(solve_index);
884}