about summary refs log tree commit diff stats
path: root/data/maps/the_partial/rooms
Commit message (Expand)AuthorAgeFilesLines
* Mark some doors as "latched"Star Rauchenberger2025-10-201-2/+0
* Added display names to portsStar Rauchenberger2025-09-282-0/+2
* [Data] Annotate shuffleable portsStar Rauchenberger2025-09-212-2/+6
* Added keyholder sanityStar Rauchenberger2025-09-021-0/+1
* Changed how door location names are formattedStar Rauchenberger2025-08-305-5/+0
* Converted puzzle symbols to an enumStar Rauchenberger2025-08-203-19/+19
* Added the_partialStar Rauchenberger2025-08-175-0/+178
5 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

































































































































































                                                                              
#include "ap_state.h"

#include <hkutil/string.h>

#include <apuuid.hpp>
#include <chrono>
#include <exception>
#include <list>
#include <thread>

constexpr int AP_MAJOR = 0;
constexpr int AP_MINOR = 4;
constexpr int AP_REVISION = 0;

constexpr int ITEM_HANDLING = 7;  // <- all

APState::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();
}

void APState::Connect(std::string server, std::string player,
                      std::string password) {
  tracker_frame_->SetStatusMessage("Connecting to Archipelago server....");

  {
    std::lock_guard client_guard(client_mutex_);

    if (apclient_) {
      apclient_->reset();
    }

    apclient_ = std::make_unique<APClient>(ap_get_uuid(""), "Lingo", server);
  }

  inventory_.clear();
  checked_locations_.clear();

  bool connected = false;
  bool has_connection_result = false;

  apclient_->set_room_info_handler([&]() {
    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(
      [&](const std::list<int64_t>& locations) {
        for (const int64_t location_id : locations) {
          checked_locations_.insert(location_id);
          std::cout << "Location: " << location_id << std::endl;
        }

        tracker_frame_->Refresh();
      });

  apclient_->set_slot_disconnected_handler([&]() {
    tracker_frame_->SetStatusMessage("Disconnected from Archipelago.");
  });

  apclient_->set_socket_disconnected_handler([&]() {
    tracker_frame_->SetStatusMessage("Disconnected from Archipelago.");
  });

  apclient_->set_items_received_handler(
      [&](const std::list<APClient::NetworkItem>& items) {
        for (const APClient::NetworkItem& item : items) {
          // TODO: Progressive items.

          inventory_.insert(item.item);
          std::cout << "Item: " << item.item << std::endl;
        }

        tracker_frame_->Refresh();
      });

  apclient_->set_slot_connected_handler([&](const nlohmann::json& slot_data) {
    tracker_frame_->SetStatusMessage("Connected to Archipelago!");

    connected = true;
    has_connection_result = true;
  });

  apclient_->set_slot_refused_handler(
      [&](const std::list<std::string>& errors) {
        connected = false;
        has_connection_result = true;

        tracker_frame_->SetStatusMessage("Disconnected from Archipelago.");

        std::vector<std::string> 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.");
          }
        }

        std::string full_message = hatkirby::implode(error_messages, " ");

        wxMessageBox(full_message, "Connection failed", wxOK | wxICON_ERROR);
      });

  client_active_ = 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;

      tracker_frame_->SetStatusMessage("Disconnected from Archipelago.");

      wxMessageBox("Timeout while connecting to Archipelago server.",
                   "Connection failed", wxOK | wxICON_ERROR);
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(100));

    interval--;
  }

  if (!connected) {
    client_active_ = false;
  }
}

APState& GetAPState() {
  static APState* instance = new APState();
  return *instance;
}