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.cpp163
1 files changed, 118 insertions, 45 deletions
diff --git a/src/ap_state.cpp b/src/ap_state.cpp index 4fd241a..a7565cf 100644 --- a/src/ap_state.cpp +++ b/src/ap_state.cpp
@@ -21,7 +21,6 @@
21#include <tuple> 21#include <tuple>
22 22
23#include "game_data.h" 23#include "game_data.h"
24#include "logger.h"
25#include "tracker_frame.h" 24#include "tracker_frame.h"
26#include "tracker_state.h" 25#include "tracker_state.h"
27 26
@@ -72,11 +71,12 @@ struct APState {
72 bool sunwarp_shuffle = false; 71 bool sunwarp_shuffle = false;
73 72
74 std::map<std::string, std::string> painting_mapping; 73 std::map<std::string, std::string> painting_mapping;
74 std::set<std::string> painting_codomain;
75 std::map<int, SunwarpMapping> sunwarp_mapping; 75 std::map<int, SunwarpMapping> sunwarp_mapping;
76 76
77 void Connect(std::string server, std::string player, std::string password) { 77 void Connect(std::string server, std::string player, std::string password) {
78 if (!initialized) { 78 if (!initialized) {
79 TrackerLog("Initializing APState..."); 79 wxLogVerbose("Initializing APState...");
80 80
81 std::thread([this]() { 81 std::thread([this]() {
82 for (;;) { 82 for (;;) {
@@ -104,15 +104,16 @@ struct APState {
104 } 104 }
105 105
106 tracked_data_storage_keys.push_back("PlayerPos"); 106 tracked_data_storage_keys.push_back("PlayerPos");
107 tracked_data_storage_keys.push_back("Paintings");
107 108
108 initialized = true; 109 initialized = true;
109 } 110 }
110 111
111 tracker_frame->SetStatusMessage("Connecting to Archipelago server...."); 112 tracker_frame->SetStatusMessage("Connecting to Archipelago server....");
112 TrackerLog("Connecting to Archipelago server (" + server + ")..."); 113 wxLogStatus("Connecting to Archipelago server (%s)...", server);
113 114
114 { 115 {
115 TrackerLog("Destroying old AP client..."); 116 wxLogVerbose("Destroying old AP client...");
116 117
117 std::lock_guard client_guard(client_mutex); 118 std::lock_guard client_guard(client_mutex);
118 119
@@ -139,6 +140,7 @@ struct APState {
139 color_shuffle = false; 140 color_shuffle = false;
140 painting_shuffle = false; 141 painting_shuffle = false;
141 painting_mapping.clear(); 142 painting_mapping.clear();
143 painting_codomain.clear();
142 mastery_requirement = 21; 144 mastery_requirement = 21;
143 level_2_requirement = 223; 145 level_2_requirement = 223;
144 location_checks = kNORMAL_LOCATIONS; 146 location_checks = kNORMAL_LOCATIONS;
@@ -151,16 +153,17 @@ struct APState {
151 sunwarp_shuffle = false; 153 sunwarp_shuffle = false;
152 sunwarp_mapping.clear(); 154 sunwarp_mapping.clear();
153 155
156 std::mutex connection_mutex;
154 connected = false; 157 connected = false;
155 has_connection_result = false; 158 has_connection_result = false;
156 159
157 apclient->set_room_info_handler([this, player, password]() { 160 apclient->set_room_info_handler([this, player, password]() {
158 inventory.clear(); 161 inventory.clear();
159 162
160 TrackerLog("Connected to Archipelago server. Authenticating as " + 163 wxLogStatus("Connected to Archipelago server. Authenticating as %s %s",
161 player + 164 player,
162 (password.empty() ? " without password" 165 (password.empty() ? "without password"
163 : " with password " + password)); 166 : "with password " + password));
164 tracker_frame->SetStatusMessage( 167 tracker_frame->SetStatusMessage(
165 "Connected to Archipelago server. Authenticating..."); 168 "Connected to Archipelago server. Authenticating...");
166 169
@@ -172,23 +175,23 @@ struct APState {
172 [this](const std::list<int64_t>& locations) { 175 [this](const std::list<int64_t>& locations) {
173 for (const int64_t location_id : locations) { 176 for (const int64_t location_id : locations) {
174 checked_locations.insert(location_id); 177 checked_locations.insert(location_id);
175 TrackerLog("Location: " + std::to_string(location_id)); 178 wxLogVerbose("Location: %lld", location_id);
176 } 179 }
177 180
178 RefreshTracker(); 181 RefreshTracker(false);
179 }); 182 });
180 183
181 apclient->set_slot_disconnected_handler([this]() { 184 apclient->set_slot_disconnected_handler([this]() {
182 tracker_frame->SetStatusMessage( 185 tracker_frame->SetStatusMessage(
183 "Disconnected from Archipelago. Attempting to reconnect..."); 186 "Disconnected from Archipelago. Attempting to reconnect...");
184 TrackerLog( 187 wxLogStatus(
185 "Slot disconnected from Archipelago. Attempting to reconnect..."); 188 "Slot disconnected from Archipelago. Attempting to reconnect...");
186 }); 189 });
187 190
188 apclient->set_socket_disconnected_handler([this]() { 191 apclient->set_socket_disconnected_handler([this]() {
189 tracker_frame->SetStatusMessage( 192 tracker_frame->SetStatusMessage(
190 "Disconnected from Archipelago. Attempting to reconnect..."); 193 "Disconnected from Archipelago. Attempting to reconnect...");
191 TrackerLog( 194 wxLogStatus(
192 "Socket disconnected from Archipelago. Attempting to reconnect..."); 195 "Socket disconnected from Archipelago. Attempting to reconnect...");
193 }); 196 });
194 197
@@ -196,10 +199,10 @@ struct APState {
196 [this](const std::list<APClient::NetworkItem>& items) { 199 [this](const std::list<APClient::NetworkItem>& items) {
197 for (const APClient::NetworkItem& item : items) { 200 for (const APClient::NetworkItem& item : items) {
198 inventory[item.item]++; 201 inventory[item.item]++;
199 TrackerLog("Item: " + std::to_string(item.item)); 202 wxLogVerbose("Item: %lld", item.item);
200 } 203 }
201 204
202 RefreshTracker(); 205 RefreshTracker(false);
203 }); 206 });
204 207
205 apclient->set_retrieved_handler( 208 apclient->set_retrieved_handler(
@@ -208,20 +211,20 @@ struct APState {
208 HandleDataStorage(key, value); 211 HandleDataStorage(key, value);
209 } 212 }
210 213
211 RefreshTracker(); 214 RefreshTracker(false);
212 }); 215 });
213 216
214 apclient->set_set_reply_handler([this](const std::string& key, 217 apclient->set_set_reply_handler([this](const std::string& key,
215 const nlohmann::json& value, 218 const nlohmann::json& value,
216 const nlohmann::json&) { 219 const nlohmann::json&) {
217 HandleDataStorage(key, value); 220 HandleDataStorage(key, value);
218 RefreshTracker(); 221 RefreshTracker(false);
219 }); 222 });
220 223
221 apclient->set_slot_connected_handler([this]( 224 apclient->set_slot_connected_handler([this, &connection_mutex](
222 const nlohmann::json& slot_data) { 225 const nlohmann::json& slot_data) {
223 tracker_frame->SetStatusMessage("Connected to Archipelago!"); 226 tracker_frame->SetStatusMessage("Connected to Archipelago!");
224 TrackerLog("Connected to Archipelago!"); 227 wxLogStatus("Connected to Archipelago!");
225 228
226 data_storage_prefix = 229 data_storage_prefix =
227 "Lingo_" + std::to_string(apclient->get_player_number()) + "_"; 230 "Lingo_" + std::to_string(apclient->get_player_number()) + "_";
@@ -266,6 +269,7 @@ struct APState {
266 for (const auto& mapping_it : 269 for (const auto& mapping_it :
267 slot_data["painting_entrance_to_exit"].items()) { 270 slot_data["painting_entrance_to_exit"].items()) {
268 painting_mapping[mapping_it.key()] = mapping_it.value(); 271 painting_mapping[mapping_it.key()] = mapping_it.value();
272 painting_codomain.insert(mapping_it.value());
269 } 273 }
270 } 274 }
271 275
@@ -281,11 +285,6 @@ struct APState {
281 } 285 }
282 } 286 }
283 287
284 connected = true;
285 has_connection_result = true;
286
287 RefreshTracker();
288
289 std::list<std::string> corrected_keys; 288 std::list<std::string> corrected_keys;
290 for (const std::string& key : tracked_data_storage_keys) { 289 for (const std::string& key : tracked_data_storage_keys) {
291 corrected_keys.push_back(data_storage_prefix + key); 290 corrected_keys.push_back(data_storage_prefix + key);
@@ -302,12 +301,23 @@ struct APState {
302 301
303 apclient->Get(corrected_keys); 302 apclient->Get(corrected_keys);
304 apclient->SetNotify(corrected_keys); 303 apclient->SetNotify(corrected_keys);
304
305 {
306 std::lock_guard connection_lock(connection_mutex);
307 if (!has_connection_result) {
308 connected = true;
309 has_connection_result = true;
310 }
311 }
305 }); 312 });
306 313
307 apclient->set_slot_refused_handler( 314 apclient->set_slot_refused_handler(
308 [this](const std::list<std::string>& errors) { 315 [this, &connection_mutex](const std::list<std::string>& errors) {
309 connected = false; 316 {
310 has_connection_result = true; 317 std::lock_guard connection_lock(connection_mutex);
318 connected = false;
319 has_connection_result = true;
320 }
311 321
312 tracker_frame->SetStatusMessage("Disconnected from Archipelago."); 322 tracker_frame->SetStatusMessage("Disconnected from Archipelago.");
313 323
@@ -336,7 +346,7 @@ struct APState {
336 } 346 }
337 347
338 std::string full_message = hatkirby::implode(error_messages, " "); 348 std::string full_message = hatkirby::implode(error_messages, " ");
339 TrackerLog(full_message); 349 wxLogError(wxString(full_message));
340 350
341 wxMessageBox(full_message, "Connection failed", wxOK | wxICON_ERROR); 351 wxMessageBox(full_message, "Connection failed", wxOK | wxICON_ERROR);
342 }); 352 });
@@ -346,18 +356,29 @@ struct APState {
346 int timeout = 5000; // 5 seconds 356 int timeout = 5000; // 5 seconds
347 int interval = 100; 357 int interval = 100;
348 int remaining_loops = timeout / interval; 358 int remaining_loops = timeout / interval;
349 while (!has_connection_result) { 359 while (true) {
350 if (interval == 0) { 360 {
351 connected = false; 361 std::lock_guard connection_lock(connection_mutex);
352 has_connection_result = true; 362 if (has_connection_result) {
363 break;
364 }
365 }
353 366
367 if (interval == 0) {
354 DestroyClient(); 368 DestroyClient();
355 369
356 tracker_frame->SetStatusMessage("Disconnected from Archipelago."); 370 tracker_frame->SetStatusMessage("Disconnected from Archipelago.");
357 371 wxLogStatus("Timeout while connecting to Archipelago server.");
358 TrackerLog("Timeout while connecting to Archipelago server.");
359 wxMessageBox("Timeout while connecting to Archipelago server.", 372 wxMessageBox("Timeout while connecting to Archipelago server.",
360 "Connection failed", wxOK | wxICON_ERROR); 373 "Connection failed", wxOK | wxICON_ERROR);
374
375 {
376 std::lock_guard connection_lock(connection_mutex);
377 connected = false;
378 has_connection_result = true;
379 }
380
381 break;
361 } 382 }
362 383
363 std::this_thread::sleep_for(std::chrono::milliseconds(100)); 384 std::this_thread::sleep_for(std::chrono::milliseconds(100));
@@ -366,7 +387,8 @@ struct APState {
366 } 387 }
367 388
368 if (connected) { 389 if (connected) {
369 RefreshTracker(); 390 ResetReachabilityRequirements();
391 RefreshTracker(true);
370 } else { 392 } else {
371 client_active = false; 393 client_active = false;
372 } 394 }
@@ -375,12 +397,11 @@ struct APState {
375 void HandleDataStorage(const std::string& key, const nlohmann::json& value) { 397 void HandleDataStorage(const std::string& key, const nlohmann::json& value) {
376 if (value.is_boolean()) { 398 if (value.is_boolean()) {
377 data_storage[key] = value.get<bool>(); 399 data_storage[key] = value.get<bool>();
378 TrackerLog("Data storage " + key + " retrieved as " + 400 wxLogVerbose("Data storage %s retrieved as %s", key,
379 (value.get<bool>() ? "true" : "false")); 401 (value.get<bool>() ? "true" : "false"));
380 } else if (value.is_number()) { 402 } else if (value.is_number()) {
381 data_storage[key] = value.get<int>(); 403 data_storage[key] = value.get<int>();
382 TrackerLog("Data storage " + key + " retrieved as " + 404 wxLogVerbose("Data storage %s retrieved as %d", key, value.get<int>());
383 std::to_string(value.get<int>()));
384 } else if (value.is_object()) { 405 } else if (value.is_object()) {
385 if (key.ends_with("PlayerPos")) { 406 if (key.ends_with("PlayerPos")) {
386 auto map_value = value.get<std::map<std::string, int>>(); 407 auto map_value = value.get<std::map<std::string, int>>();
@@ -389,7 +410,7 @@ struct APState {
389 data_storage[key] = value.get<std::map<std::string, int>>(); 410 data_storage[key] = value.get<std::map<std::string, int>>();
390 } 411 }
391 412
392 TrackerLog("Data storage " + key + " retrieved as dictionary"); 413 wxLogVerbose("Data storage %s retrieved as dictionary", key);
393 } else if (value.is_null()) { 414 } else if (value.is_null()) {
394 if (key.ends_with("PlayerPos")) { 415 if (key.ends_with("PlayerPos")) {
395 player_pos = std::nullopt; 416 player_pos = std::nullopt;
@@ -397,7 +418,19 @@ struct APState {
397 data_storage.erase(key); 418 data_storage.erase(key);
398 } 419 }
399 420
400 TrackerLog("Data storage " + key + " retrieved as null"); 421 wxLogVerbose("Data storage %s retrieved as null", key);
422 } else if (value.is_array()) {
423 auto list_value = value.get<std::vector<std::string>>();
424
425 if (key.ends_with("Paintings")) {
426 data_storage[key] =
427 std::set<std::string>(list_value.begin(), list_value.end());
428 } else {
429 data_storage[key] = list_value;
430 }
431
432 wxLogVerbose("Data storage %s retrieved as list: [%s]", key,
433 hatkirby::implode(list_value, ", "));
401 } 434 }
402 } 435 }
403 436
@@ -420,22 +453,46 @@ struct APState {
420 return data_storage.count(key) && std::any_cast<bool>(data_storage.at(key)); 453 return data_storage.count(key) && std::any_cast<bool>(data_storage.at(key));
421 } 454 }
422 455
423 void RefreshTracker() { 456 const std::set<std::string>& GetCheckedPaintings() {
424 TrackerLog("Refreshing display..."); 457 std::string key = data_storage_prefix + "Paintings";
458 if (!data_storage.count(key)) {
459 data_storage[key] = std::set<std::string>();
460 }
461
462 return std::any_cast<const std::set<std::string>&>(data_storage.at(key));
463 }
464
465 bool IsPaintingChecked(const std::string& painting_id) {
466 const auto& checked_paintings = GetCheckedPaintings();
467
468 return checked_paintings.count(painting_id) ||
469 (painting_mapping.count(painting_id) &&
470 checked_paintings.count(painting_mapping.at(painting_id)));
471 }
472
473 void RefreshTracker(bool reset) {
474 wxLogVerbose("Refreshing display...");
425 475
426 RecalculateReachability(); 476 RecalculateReachability();
427 tracker_frame->UpdateIndicators(); 477
478 if (reset) {
479 tracker_frame->ResetIndicators();
480 } else {
481 tracker_frame->UpdateIndicators();
482 }
428 } 483 }
429 484
430 int64_t GetItemId(const std::string& item_name) { 485 int64_t GetItemId(const std::string& item_name) {
431 int64_t ap_id = apclient->get_item_id(item_name); 486 int64_t ap_id = apclient->get_item_id(item_name);
432 if (ap_id == APClient::INVALID_NAME_ID) { 487 if (ap_id == APClient::INVALID_NAME_ID) {
433 TrackerLog("Could not find AP item ID for " + item_name); 488 wxLogError("Could not find AP item ID for %s", item_name);
434 } 489 }
435 490
436 return ap_id; 491 return ap_id;
437 } 492 }
438 493
494 std::string GetItemName(int id) { return apclient->get_item_name(id); }
495
439 bool HasReachedGoal() { 496 bool HasReachedGoal() {
440 return data_storage.count(victory_data_storage_key) && 497 return data_storage.count(victory_data_storage_key) &&
441 std::any_cast<int>(data_storage.at(victory_data_storage_key)) == 498 std::any_cast<int>(data_storage.at(victory_data_storage_key)) ==
@@ -474,6 +531,10 @@ bool AP_HasItem(int item_id, int quantity) {
474 return GetState().HasItem(item_id, quantity); 531 return GetState().HasItem(item_id, quantity);
475} 532}
476 533
534std::string AP_GetItemName(int item_id) {
535 return GetState().GetItemName(item_id);
536}
537
477DoorShuffleMode AP_GetDoorShuffleMode() { return GetState().door_shuffle_mode; } 538DoorShuffleMode AP_GetDoorShuffleMode() { return GetState().door_shuffle_mode; }
478 539
479bool AP_AreDoorsGrouped() { return GetState().group_doors; } 540bool AP_AreDoorsGrouped() { return GetState().group_doors; }
@@ -482,10 +543,22 @@ bool AP_IsColorShuffle() { return GetState().color_shuffle; }
482 543
483bool AP_IsPaintingShuffle() { return GetState().painting_shuffle; } 544bool AP_IsPaintingShuffle() { return GetState().painting_shuffle; }
484 545
485const std::map<std::string, std::string> AP_GetPaintingMapping() { 546const std::map<std::string, std::string>& AP_GetPaintingMapping() {
486 return GetState().painting_mapping; 547 return GetState().painting_mapping;
487} 548}
488 549
550bool AP_IsPaintingMappedTo(const std::string& painting_id) {
551 return GetState().painting_codomain.count(painting_id);
552}
553
554const std::set<std::string>& AP_GetCheckedPaintings() {
555 return GetState().GetCheckedPaintings();
556}
557
558bool AP_IsPaintingChecked(const std::string& painting_id) {
559 return GetState().IsPaintingChecked(painting_id);
560}
561
489int AP_GetMasteryRequirement() { return GetState().mastery_requirement; } 562int AP_GetMasteryRequirement() { return GetState().mastery_requirement; }
490 563
491int AP_GetLevel2Requirement() { return GetState().level_2_requirement; } 564int AP_GetLevel2Requirement() { return GetState().level_2_requirement; }