From d7212d755dca7f4fd99cf4b775cd0d372d7bcbb2 Mon Sep 17 00:00:00 2001 From: Star Rauchenberger Date: Fri, 5 May 2023 16:35:09 -0400 Subject: Refactored away singletons (Except TrackerConfig, for now at least) --- src/ap_state.cpp | 476 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 251 insertions(+), 225 deletions(-) (limited to 'src/ap_state.cpp') diff --git a/src/ap_state.cpp b/src/ap_state.cpp index 69c9e9f..efbca8c 100644 --- a/src/ap_state.cpp +++ b/src/ap_state.cpp @@ -31,307 +31,333 @@ constexpr int ITEM_HANDLING = 7; // <- all namespace { -APClient* apclient = nullptr; +struct APState { + std::unique_ptr apclient; -bool initialized = false; + bool initialized = false; -TrackerFrame* tracker_frame; + TrackerFrame* tracker_frame = nullptr; -bool client_active = false; -std::mutex client_mutex; + bool client_active = false; + std::mutex client_mutex; -bool connected = false; -bool has_connection_result = false; + bool connected = false; + bool has_connection_result = false; -std::map inventory; -std::set checked_locations; + std::map inventory; + std::set checked_locations; -std::map, int64_t> ap_id_by_location_id; -std::map ap_id_by_item_name; -std::map ap_id_by_color; -std::map progressive_item_by_ap_id; + std::map, int64_t> ap_id_by_location_id; + std::map ap_id_by_item_name; + std::map ap_id_by_color; + std::map progressive_item_by_ap_id; -DoorShuffleMode door_shuffle_mode = kNO_DOORS; -bool color_shuffle = false; -bool painting_shuffle = false; -int mastery_requirement = 21; + DoorShuffleMode door_shuffle_mode = kNO_DOORS; + bool color_shuffle = false; + bool painting_shuffle = false; + int mastery_requirement = 21; -std::map painting_mapping; + std::map painting_mapping; -void RefreshTracker() { - GetTrackerState().CalculateState(); - tracker_frame->UpdateIndicators(); -} - -int64_t GetItemId(const std::string& item_name) { - int64_t ap_id = apclient->get_item_id(item_name); - if (ap_id == APClient::INVALID_NAME_ID) { - std::cout << "Could not find AP item ID for " << item_name << std::endl; - } + void Connect(std::string server, std::string player, std::string password) { + if (!initialized) { + std::thread([this]() { + for (;;) { + { + std::lock_guard client_guard(client_mutex); + if (apclient) { + apclient->poll(); + } + } - return ap_id; -} + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + }).detach(); -void DestroyClient() { - client_active = false; - apclient->reset(); - delete apclient; - apclient = nullptr; -} + initialized = true; + } -} // namespace + tracker_frame->SetStatusMessage("Connecting to Archipelago server...."); -void AP_SetTrackerFrame(TrackerFrame* arg) { tracker_frame = arg; } + { + std::lock_guard client_guard(client_mutex); -void AP_Connect(std::string server, std::string player, std::string password) { - if (!initialized) { - std::thread([]() { - for (;;) { - { - std::lock_guard client_guard(client_mutex); - if (apclient) { - apclient->poll(); - } - } + if (apclient) { + DestroyClient(); + } - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::string cert_store = ""; + if (std::filesystem::exists(CERT_STORE_PATH)) { + cert_store = CERT_STORE_PATH; } - }).detach(); - initialized = true; - } + apclient = std::make_unique(ap_get_uuid(""), "Lingo", server, + cert_store); + } - tracker_frame->SetStatusMessage("Connecting to Archipelago server...."); + inventory.clear(); + checked_locations.clear(); + door_shuffle_mode = kNO_DOORS; + color_shuffle = false; + painting_shuffle = false; + painting_mapping.clear(); + mastery_requirement = 21; - { - std::lock_guard client_guard(client_mutex); + connected = false; + has_connection_result = false; - if (apclient) { - DestroyClient(); - } + apclient->set_room_info_handler([this, player, password]() { + inventory.clear(); - std::string cert_store = ""; - if (std::filesystem::exists(CERT_STORE_PATH)) { - cert_store = CERT_STORE_PATH; - } + tracker_frame->SetStatusMessage( + "Connected to Archipelago server. Authenticating..."); - apclient = new APClient(ap_get_uuid(""), "Lingo", server, cert_store); - } + apclient->ConnectSlot(player, password, ITEM_HANDLING, {"Tracker"}, + {AP_MAJOR, AP_MINOR, AP_REVISION}); + }); - inventory.clear(); - checked_locations.clear(); - door_shuffle_mode = kNO_DOORS; - color_shuffle = false; - painting_shuffle = false; - painting_mapping.clear(); - mastery_requirement = 21; + apclient->set_location_checked_handler( + [this](const std::list& locations) { + for (const int64_t location_id : locations) { + checked_locations.insert(location_id); + std::cout << "Location: " << location_id << std::endl; + } - connected = false; - has_connection_result = false; + RefreshTracker(); + }); - apclient->set_room_info_handler([player, password]() { - inventory.clear(); + apclient->set_slot_disconnected_handler([this]() { + tracker_frame->SetStatusMessage( + "Disconnected from Archipelago. Attempting to reconnect..."); + }); - tracker_frame->SetStatusMessage( - "Connected to Archipelago server. Authenticating..."); + apclient->set_socket_disconnected_handler([this]() { + tracker_frame->SetStatusMessage( + "Disconnected from Archipelago. Attempting to reconnect..."); + }); - apclient->ConnectSlot(player, password, ITEM_HANDLING, {"Tracker"}, - {AP_MAJOR, AP_MINOR, AP_REVISION}); - }); + apclient->set_items_received_handler( + [this](const std::list& items) { + for (const APClient::NetworkItem& item : items) { + inventory[item.item]++; + std::cout << "Item: " << item.item << std::endl; + } - apclient->set_location_checked_handler( - [](const std::list& locations) { - for (const int64_t location_id : locations) { - checked_locations.insert(location_id); - std::cout << "Location: " << location_id << std::endl; - } + RefreshTracker(); + }); - RefreshTracker(); - }); + apclient->set_slot_connected_handler([this]( + const nlohmann::json& slot_data) { + tracker_frame->SetStatusMessage("Connected to Archipelago!"); - apclient->set_slot_disconnected_handler([]() { - tracker_frame->SetStatusMessage( - "Disconnected from Archipelago. Attempting to reconnect..."); - }); + door_shuffle_mode = slot_data["shuffle_doors"].get(); + color_shuffle = slot_data["shuffle_colors"].get(); + painting_shuffle = slot_data["shuffle_paintings"].get(); + mastery_requirement = slot_data["mastery_achievements"].get(); - apclient->set_socket_disconnected_handler([]() { - tracker_frame->SetStatusMessage( - "Disconnected from Archipelago. Attempting to reconnect..."); - }); + if (painting_shuffle && slot_data.contains("painting_entrance_to_exit")) { + painting_mapping.clear(); - apclient->set_items_received_handler( - [](const std::list& items) { - for (const APClient::NetworkItem& item : items) { - inventory[item.item]++; - std::cout << "Item: " << item.item << std::endl; + for (const auto& mapping_it : + slot_data["painting_entrance_to_exit"].items()) { + painting_mapping[mapping_it.key()] = mapping_it.value(); } + } - RefreshTracker(); - }); + connected = true; + has_connection_result = true; - apclient->set_slot_connected_handler([](const nlohmann::json& slot_data) { - tracker_frame->SetStatusMessage("Connected to Archipelago!"); + RefreshTracker(); + }); + + apclient->set_slot_refused_handler( + [this](const std::list& errors) { + connected = false; + has_connection_result = true; + + tracker_frame->SetStatusMessage("Disconnected from Archipelago."); + + std::vector error_messages; + error_messages.push_back("Could not connect to Archipelago."); + + for (const std::string& error : errors) { + if (error == "InvalidSlot") { + error_messages.push_back("Invalid player name."); + } else if (error == "InvalidGame") { + error_messages.push_back( + "The specified player is not playing Lingo."); + } else if (error == "IncompatibleVersion") { + error_messages.push_back( + "The Archipelago server is not the correct version for this " + "client."); + } else if (error == "InvalidPassword") { + error_messages.push_back("Incorrect password."); + } else if (error == "InvalidItemsHandling") { + error_messages.push_back( + "Invalid item handling flag. This is a bug with the tracker. " + "Please report it to the lingo-ap-tracker GitHub."); + } else { + error_messages.push_back("Unknown error."); + } + } - door_shuffle_mode = slot_data["shuffle_doors"].get(); - color_shuffle = slot_data["shuffle_colors"].get(); - painting_shuffle = slot_data["shuffle_paintings"].get(); - mastery_requirement = slot_data["mastery_achievements"].get(); + std::string full_message = hatkirby::implode(error_messages, " "); - if (painting_shuffle && slot_data.contains("painting_entrance_to_exit")) { - painting_mapping.clear(); + wxMessageBox(full_message, "Connection failed", wxOK | wxICON_ERROR); + }); - for (const auto& mapping_it : - slot_data["painting_entrance_to_exit"].items()) { - painting_mapping[mapping_it.key()] = mapping_it.value(); - } - } + client_active = true; - connected = true; - has_connection_result = true; + int timeout = 5000; // 5 seconds + int interval = 100; + int remaining_loops = timeout / interval; + while (!has_connection_result) { + if (interval == 0) { + connected = false; + has_connection_result = true; - RefreshTracker(); - }); + DestroyClient(); - apclient->set_slot_refused_handler([](const std::list& errors) { - connected = false; - has_connection_result = true; - - tracker_frame->SetStatusMessage("Disconnected from Archipelago."); - - std::vector error_messages; - error_messages.push_back("Could not connect to Archipelago."); - - for (const std::string& error : errors) { - if (error == "InvalidSlot") { - error_messages.push_back("Invalid player name."); - } else if (error == "InvalidGame") { - error_messages.push_back("The specified player is not playing Lingo."); - } else if (error == "IncompatibleVersion") { - error_messages.push_back( - "The Archipelago server is not the correct version for this " - "client."); - } else if (error == "InvalidPassword") { - error_messages.push_back("Incorrect password."); - } else if (error == "InvalidItemsHandling") { - error_messages.push_back( - "Invalid item handling flag. This is a bug with the tracker. " - "Please report it to the lingo-ap-tracker GitHub."); - } else { - error_messages.push_back("Unknown error."); + tracker_frame->SetStatusMessage("Disconnected from Archipelago."); + + wxMessageBox("Timeout while connecting to Archipelago server.", + "Connection failed", wxOK | wxICON_ERROR); } - } - std::string full_message = hatkirby::implode(error_messages, " "); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); - wxMessageBox(full_message, "Connection failed", wxOK | wxICON_ERROR); - }); + interval--; + } - client_active = true; + if (connected) { + for (const MapArea& map_area : GD_GetMapAreas()) { + for (int section_id = 0; section_id < map_area.locations.size(); + section_id++) { + const Location& location = map_area.locations.at(section_id); + + int64_t ap_id = apclient->get_location_id(location.ap_location_name); + if (ap_id == APClient::INVALID_NAME_ID) { + std::cout << "Could not find AP location ID for " + << location.ap_location_name << std::endl; + } else { + ap_id_by_location_id[{map_area.id, section_id}] = ap_id; + } + } + } - int timeout = 5000; // 5 seconds - int interval = 100; - int remaining_loops = timeout / interval; - while (!has_connection_result) { - if (interval == 0) { - connected = false; - has_connection_result = true; + for (const Door& door : GD_GetDoors()) { + if (!door.skip_item) { + ap_id_by_item_name[door.item_name] = GetItemId(door.item_name); - DestroyClient(); + if (!door.group_name.empty() && + !ap_id_by_item_name.count(door.group_name)) { + ap_id_by_item_name[door.group_name] = GetItemId(door.group_name); + } - tracker_frame->SetStatusMessage("Disconnected from Archipelago."); + for (const ProgressiveRequirement& prog_req : door.progressives) { + ap_id_by_item_name[prog_req.item_name] = + GetItemId(prog_req.item_name); + } + } + } - wxMessageBox("Timeout while connecting to Archipelago server.", - "Connection failed", wxOK | wxICON_ERROR); + ap_id_by_color[LingoColor::kBlack] = GetItemId("Black"); + ap_id_by_color[LingoColor::kRed] = GetItemId("Red"); + ap_id_by_color[LingoColor::kBlue] = GetItemId("Blue"); + ap_id_by_color[LingoColor::kYellow] = GetItemId("Yellow"); + ap_id_by_color[LingoColor::kPurple] = GetItemId("Purple"); + ap_id_by_color[LingoColor::kOrange] = GetItemId("Orange"); + ap_id_by_color[LingoColor::kGreen] = GetItemId("Green"); + ap_id_by_color[LingoColor::kBrown] = GetItemId("Brown"); + ap_id_by_color[LingoColor::kGray] = GetItemId("Gray"); + + RefreshTracker(); + } else { + client_active = false; } + } - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + bool HasCheckedGameLocation(int area_id, int section_id) { + std::tuple location_key = {area_id, section_id}; - interval--; + if (ap_id_by_location_id.count(location_key)) { + return checked_locations.count(ap_id_by_location_id.at(location_key)); + } else { + return false; + } } - if (connected) { - for (const MapArea& map_area : GetGameData().GetMapAreas()) { - for (int section_id = 0; section_id < map_area.locations.size(); - section_id++) { - const Location& location = map_area.locations.at(section_id); - - int64_t ap_id = apclient->get_location_id(location.ap_location_name); - if (ap_id == APClient::INVALID_NAME_ID) { - std::cout << "Could not find AP location ID for " - << location.ap_location_name << std::endl; - } else { - ap_id_by_location_id[{map_area.id, section_id}] = ap_id; - } - } + bool HasColorItem(LingoColor color) { + if (ap_id_by_color.count(color)) { + return inventory.count(ap_id_by_color.at(color)); + } else { + return false; } + } - for (const Door& door : GetGameData().GetDoors()) { - if (!door.skip_item) { - ap_id_by_item_name[door.item_name] = GetItemId(door.item_name); + bool HasItem(const std::string& item, int quantity) { + if (ap_id_by_item_name.count(item)) { + int64_t ap_id = ap_id_by_item_name.at(item); + return inventory.count(ap_id) && inventory.at(ap_id) >= quantity; + } else { + return false; + } + } - if (!door.group_name.empty() && - !ap_id_by_item_name.count(door.group_name)) { - ap_id_by_item_name[door.group_name] = GetItemId(door.group_name); - } + void RefreshTracker() { + RecalculateReachability(); + tracker_frame->UpdateIndicators(); + } - for (const ProgressiveRequirement& prog_req : door.progressives) { - ap_id_by_item_name[prog_req.item_name] = - GetItemId(prog_req.item_name); - } - } + int64_t GetItemId(const std::string& item_name) { + int64_t ap_id = apclient->get_item_id(item_name); + if (ap_id == APClient::INVALID_NAME_ID) { + std::cout << "Could not find AP item ID for " << item_name << std::endl; } - ap_id_by_color[LingoColor::kBlack] = GetItemId("Black"); - ap_id_by_color[LingoColor::kRed] = GetItemId("Red"); - ap_id_by_color[LingoColor::kBlue] = GetItemId("Blue"); - ap_id_by_color[LingoColor::kYellow] = GetItemId("Yellow"); - ap_id_by_color[LingoColor::kPurple] = GetItemId("Purple"); - ap_id_by_color[LingoColor::kOrange] = GetItemId("Orange"); - ap_id_by_color[LingoColor::kGreen] = GetItemId("Green"); - ap_id_by_color[LingoColor::kBrown] = GetItemId("Brown"); - ap_id_by_color[LingoColor::kGray] = GetItemId("Gray"); - - RefreshTracker(); - } else { + return ap_id; + } + + void DestroyClient() { client_active = false; + apclient->reset(); + apclient.reset(); } +}; + +APState& GetState() { + static APState* instance = new APState(); + return *instance; } -bool AP_HasCheckedGameLocation(int area_id, int section_id) { - std::tuple location_key = {area_id, section_id}; +} // namespace - if (ap_id_by_location_id.count(location_key)) { - return checked_locations.count(ap_id_by_location_id.at(location_key)); - } else { - return false; - } +void AP_SetTrackerFrame(TrackerFrame* arg) { GetState().tracker_frame = arg; } + +void AP_Connect(std::string server, std::string player, std::string password) { + GetState().Connect(server, player, password); +} + +bool AP_HasCheckedGameLocation(int area_id, int section_id) { + return GetState().HasCheckedGameLocation(area_id, section_id); } bool AP_HasColorItem(LingoColor color) { - if (ap_id_by_color.count(color)) { - return inventory.count(ap_id_by_color.at(color)); - } else { - return false; - } + return GetState().HasColorItem(color); } bool AP_HasItem(const std::string& item, int quantity) { - if (ap_id_by_item_name.count(item)) { - int64_t ap_id = ap_id_by_item_name.at(item); - return inventory.count(ap_id) && inventory.at(ap_id) >= quantity; - } else { - return false; - } + return GetState().HasItem(item, quantity); } -DoorShuffleMode AP_GetDoorShuffleMode() { return door_shuffle_mode; } +DoorShuffleMode AP_GetDoorShuffleMode() { return GetState().door_shuffle_mode; } -bool AP_IsColorShuffle() { return color_shuffle; } +bool AP_IsColorShuffle() { return GetState().color_shuffle; } -bool AP_IsPaintingShuffle() { return painting_shuffle; } +bool AP_IsPaintingShuffle() { return GetState().painting_shuffle; } const std::map AP_GetPaintingMapping() { - return painting_mapping; + return GetState().painting_mapping; } -int AP_GetMasteryRequirement() { return mastery_requirement; } +int AP_GetMasteryRequirement() { return GetState().mastery_requirement; } -- cgit 1.4.1