#include "ap_state.h" #define HAS_STD_FILESYSTEM #define _WEBSOCKETPP_CPP11_STRICT_ #pragma comment(lib, "crypt32") #include #include #include #include #include #include #include #include #include #include #include #include #include "game_data.h" #include "logger.h" #include "tracker_frame.h" #include "tracker_state.h" constexpr int AP_MAJOR = 0; constexpr int AP_MINOR = 4; constexpr int AP_REVISION = 0; constexpr const char* CERT_STORE_PATH = "cacert.pem"; constexpr int ITEM_HANDLING = 7; // <- all namespace { struct APState { std::unique_ptr apclient; bool initialized = false; TrackerFrame* tracker_frame = nullptr; bool client_active = false; std::mutex client_mutex; bool connected = false; bool has_connection_result = false; std::list tracked_data_storage_keys; std::map inventory; std::set checked_locations; std::map data_storage; 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; bool reduce_checks = false; std::map painting_mapping; void Connect(std::string server, std::string player, std::string password) { if (!initialized) { TrackerLog("Initializing APState..."); std::thread([this]() { for (;;) { { std::lock_guard client_guard(client_mutex); if (apclient) { apclient->poll(); } } std::this_thread::sleep_for(std::chrono::milliseconds(100)); } }).detach(); for (int panel_id : GD_GetAchievementPanels()) { tracked_data_storage_keys.push_back( "Achievement|" + GD_GetPanel(panel_id).achievement_name); } initialized = true; } tracker_frame->SetStatusMessage("Connecting to Archipelago server...."); TrackerLog("Connecting to Archipelago server (" + server + ")..."); { TrackerLog("Destroying old AP client..."); std::lock_guard client_guard(client_mutex); if (apclient) { DestroyClient(); } std::string cert_store = ""; if (std::filesystem::exists(CERT_STORE_PATH)) { cert_store = CERT_STORE_PATH; } apclient = std::make_unique(ap_get_uuid(""), "Lingo", server, cert_store); } inventory.clear(); checked_locations.clear(); data_storage.clear(); door_shuffle_mode = kNO_DOORS; color_shuffle = false; painting_shuffle = false; painting_mapping.clear(); mastery_requirement = 21; reduce_checks = false; connected = false; has_connection_result = false; apclient->set_room_info_handler([this, player, password]() { inventory.clear(); TrackerLog("Connected to Archipelago server. Authenticating as " + player + (password.empty() ? " without password" : " with password " + password)); tracker_frame->SetStatusMessage( "Connected to Archipelago server. Authenticating..."); apclient->ConnectSlot(player, password, ITEM_HANDLING, {"Tracker"}, {AP_MAJOR, AP_MINOR, AP_REVISION}); }); apclient->set_location_checked_handler( [this](const std::list& locations) { for (const int64_t location_id : locations) { checked_locations.insert(location_id); TrackerLog("Location: " + std::to_string(location_id)); } RefreshTracker(); }); apclient->set_slot_disconnected_handler([this]() { tracker_frame->SetStatusMessage( "Disconnected from Archipelago. Attempting to reconnect..."); TrackerLog( "Slot disconnected from Archipelago. Attempting to reconnect..."); }); apclient->set_socket_disconnected_handler([this]() { tracker_frame->SetStatusMessage( "Disconnected from Archipelago. Attempting to reconnect..."); TrackerLog( "Socket disconnected from Archipelago. Attempting to reconnect..."); }); apclient->set_items_received_handler( [this](const std::list& items) { for (const APClient::NetworkItem& item : items) { inventory[item.item]++; TrackerLog("Item: " + std::to_string(item.item)); } RefreshTracker(); }); apclient->set_retrieved_handler( [this](const std::map& data) { for (const auto& [key, value] : data) { if (value.is_boolean()) { data_storage[key] = value.get(); TrackerLog("Data storage " + key + " retrieved as " + (value.get() ? "true" : "false")); } } Refr
%fieldset#content
  .title-field
    = f.label :title
    = f.text_field :title, placeholder: "Title"
  .url-field
    = f.label :url
    = f.text_field :url, placeholder: "URL"
%fieldset#details
  - if f.object.errors.any?
    #errors.details-module
      %h3 Error!
      %ul
        - f.object.errors.full_messages.each do |error|
          %li= error
  .details-module
    .tags-field
      = f.label :tag_list, "Tags"
      = f.text_field :tag_list, type: :tags, value: f.object.tag_list.join(",")
  .details-module
    = f.fields_for :records, Record.new do |builder|
      .should-create-record-field
        = builder.check_box :_destroy, {checked: false}, "0", "1"
        = builder.label :_destroy, "Create record?"
      .record-description-field
        = builder.text_area :description, placeholder: "record text"
  .details-module= f.submit