about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2024-06-10 19:13:22 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2024-06-10 19:13:22 -0400
commit33bf1f9653ed608de5554940dc8a0c3f5dc7e4ea (patch)
treeb1db5d3e83ccd8c5219d5db12b01bc3d152b79d1
parent3b3c3ca4ed98c8d1e884f6c9f8f63d7b7c76e37b (diff)
downloadlingo-ap-tracker-33bf1f9653ed608de5554940dc8a0c3f5dc7e4ea.tar.gz
lingo-ap-tracker-33bf1f9653ed608de5554940dc8a0c3f5dc7e4ea.tar.bz2
lingo-ap-tracker-33bf1f9653ed608de5554940dc8a0c3f5dc7e4ea.zip
Go back to old logging system
Brought in libfmt to handle string formatting and replace a bunch of ostringstream uses.
-rw-r--r--CMakeLists.txt5
-rw-r--r--src/ap_state.cpp79
-rw-r--r--src/game_data.cpp63
-rw-r--r--src/logger.cpp32
-rw-r--r--src/logger.h8
-rw-r--r--src/main.cpp12
-rw-r--r--src/subway_map.cpp14
-rw-r--r--src/version.h7
-rw-r--r--vcpkg.json3
9 files changed, 126 insertions, 97 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index cd62c55..f9f1117 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -10,6 +10,7 @@ find_package(wxWidgets CONFIG REQUIRED)
10find_package(OpenSSL REQUIRED) 10find_package(OpenSSL REQUIRED)
11find_package(yaml-cpp REQUIRED) 11find_package(yaml-cpp REQUIRED)
12find_package(websocketpp REQUIRED) 12find_package(websocketpp REQUIRED)
13find_package(fmt REQUIRED)
13 14
14include_directories( 15include_directories(
15 vendor/hkutil 16 vendor/hkutil
@@ -22,6 +23,7 @@ include_directories(
22 ${yaml-cpp_INCLUDE_DIRS} 23 ${yaml-cpp_INCLUDE_DIRS}
23 ${OpenSSL_INCLUDE_DIRS} 24 ${OpenSSL_INCLUDE_DIRS}
24 vendor/whereami 25 vendor/whereami
26 ${fmt_INCLUDE_DIRS}
25 vendor 27 vendor
26) 28)
27 29
@@ -45,8 +47,9 @@ add_executable(lingo_ap_tracker
45 "src/global.cpp" 47 "src/global.cpp"
46 "src/subway_map.cpp" 48 "src/subway_map.cpp"
47 "src/network_set.cpp" 49 "src/network_set.cpp"
50 "src/logger.cpp"
48 "vendor/whereami/whereami.c" 51 "vendor/whereami/whereami.c"
49) 52)
50set_property(TARGET lingo_ap_tracker PROPERTY CXX_STANDARD 20) 53set_property(TARGET lingo_ap_tracker PROPERTY CXX_STANDARD 20)
51set_property(TARGET lingo_ap_tracker PROPERTY CXX_STANDARD_REQUIRED ON) 54set_property(TARGET lingo_ap_tracker PROPERTY CXX_STANDARD_REQUIRED ON)
52target_link_libraries(lingo_ap_tracker PRIVATE OpenSSL::SSL OpenSSL::Crypto websocketpp::websocketpp wx::core wx::base wx::net yaml-cpp::yaml-cpp) 55target_link_libraries(lingo_ap_tracker PRIVATE fmt::fmt OpenSSL::SSL OpenSSL::Crypto websocketpp::websocketpp wx::core wx::base wx::net yaml-cpp::yaml-cpp)
diff --git a/src/ap_state.cpp b/src/ap_state.cpp index 8ff0ccd..e4d892b 100644 --- a/src/ap_state.cpp +++ b/src/ap_state.cpp
@@ -4,6 +4,7 @@
4#define _WEBSOCKETPP_CPP11_STRICT_ 4#define _WEBSOCKETPP_CPP11_STRICT_
5#pragma comment(lib, "crypt32") 5#pragma comment(lib, "crypt32")
6 6
7#include <fmt/core.h>
7#include <hkutil/string.h> 8#include <hkutil/string.h>
8 9
9#include <any> 10#include <any>
@@ -21,6 +22,7 @@
21#include <tuple> 22#include <tuple>
22 23
23#include "game_data.h" 24#include "game_data.h"
25#include "logger.h"
24#include "tracker_frame.h" 26#include "tracker_frame.h"
25#include "tracker_state.h" 27#include "tracker_state.h"
26 28
@@ -75,7 +77,7 @@ struct APState {
75 77
76 void Connect(std::string server, std::string player, std::string password) { 78 void Connect(std::string server, std::string player, std::string password) {
77 if (!initialized) { 79 if (!initialized) {
78 wxLogVerbose("Initializing APState..."); 80 TrackerLog("Initializing APState...");
79 81
80 std::thread([this]() { 82 std::thread([this]() {
81 for (;;) { 83 for (;;) {
@@ -91,14 +93,14 @@ struct APState {
91 }).detach(); 93 }).detach();
92 94
93 for (int panel_id : GD_GetAchievementPanels()) { 95 for (int panel_id : GD_GetAchievementPanels()) {
94 tracked_data_storage_keys.push_back( 96 tracked_data_storage_keys.push_back(fmt::format(
95 "Achievement|" + GD_GetPanel(panel_id).achievement_name); 97 "Achievement|{}", GD_GetPanel(panel_id).achievement_name));
96 } 98 }
97 99
98 for (const MapArea& map_area : GD_GetMapAreas()) { 100 for (const MapArea& map_area : GD_GetMapAreas()) {
99 for (const Location& location : map_area.locations) { 101 for (const Location& location : map_area.locations) {
100 tracked_data_storage_keys.push_back( 102 tracked_data_storage_keys.push_back(
101 "Hunt|" + std::to_string(location.ap_location_id)); 103 fmt::format("Hunt|{}", location.ap_location_id));
102 } 104 }
103 } 105 }
104 106
@@ -109,10 +111,10 @@ struct APState {
109 } 111 }
110 112
111 tracker_frame->SetStatusMessage("Connecting to Archipelago server...."); 113 tracker_frame->SetStatusMessage("Connecting to Archipelago server....");
112 wxLogStatus("Connecting to Archipelago server (%s)...", server); 114 TrackerLog(fmt::format("Connecting to Archipelago server ({})...", server));
113 115
114 { 116 {
115 wxLogVerbose("Destroying old AP client..."); 117 TrackerLog("Destroying old AP client...");
116 118
117 std::lock_guard client_guard(client_mutex); 119 std::lock_guard client_guard(client_mutex);
118 120
@@ -158,10 +160,10 @@ struct APState {
158 apclient->set_room_info_handler([this, player, password]() { 160 apclient->set_room_info_handler([this, player, password]() {
159 inventory.clear(); 161 inventory.clear();
160 162
161 wxLogStatus("Connected to Archipelago server. Authenticating as %s %s", 163 TrackerLog(fmt::format(
162 player, 164 "Connected to Archipelago server. Authenticating as {} {}", player,
163 (password.empty() ? "without password" 165 (password.empty() ? "without password"
164 : "with password " + password)); 166 : "with password " + password)));
165 tracker_frame->SetStatusMessage( 167 tracker_frame->SetStatusMessage(
166 "Connected to Archipelago server. Authenticating..."); 168 "Connected to Archipelago server. Authenticating...");
167 169
@@ -173,7 +175,7 @@ struct APState {
173 [this](const std::list<int64_t>& locations) { 175 [this](const std::list<int64_t>& locations) {
174 for (const int64_t location_id : locations) { 176 for (const int64_t location_id : locations) {
175 checked_locations.insert(location_id); 177 checked_locations.insert(location_id);
176 wxLogVerbose("Location: %lld", location_id); 178 TrackerLog(fmt::format("Location: {}", location_id));
177 } 179 }
178 180
179 RefreshTracker(false); 181 RefreshTracker(false);
@@ -182,14 +184,14 @@ struct APState {
182 apclient->set_slot_disconnected_handler([this]() { 184 apclient->set_slot_disconnected_handler([this]() {
183 tracker_frame->SetStatusMessage( 185 tracker_frame->SetStatusMessage(
184 "Disconnected from Archipelago. Attempting to reconnect..."); 186 "Disconnected from Archipelago. Attempting to reconnect...");
185 wxLogStatus( 187 TrackerLog(
186 "Slot disconnected from Archipelago. Attempting to reconnect..."); 188 "Slot disconnected from Archipelago. Attempting to reconnect...");
187 }); 189 });
188 190
189 apclient->set_socket_disconnected_handler([this]() { 191 apclient->set_socket_disconnected_handler([this]() {
190 tracker_frame->SetStatusMessage( 192 tracker_frame->SetStatusMessage(
191 "Disconnected from Archipelago. Attempting to reconnect..."); 193 "Disconnected from Archipelago. Attempting to reconnect...");
192 wxLogStatus( 194 TrackerLog(
193 "Socket disconnected from Archipelago. Attempting to reconnect..."); 195 "Socket disconnected from Archipelago. Attempting to reconnect...");
194 }); 196 });
195 197
@@ -197,7 +199,7 @@ struct APState {
197 [this](const std::list<APClient::NetworkItem>& items) { 199 [this](const std::list<APClient::NetworkItem>& items) {
198 for (const APClient::NetworkItem& item : items) { 200 for (const APClient::NetworkItem& item : items) {
199 inventory[item.item]++; 201 inventory[item.item]++;
200 wxLogVerbose("Item: %lld", item.item); 202 TrackerLog(fmt::format("Item: {}", item.item));
201 } 203 }
202 204
203 RefreshTracker(false); 205 RefreshTracker(false);
@@ -222,10 +224,10 @@ struct APState {
222 apclient->set_slot_connected_handler([this, &connection_mutex]( 224 apclient->set_slot_connected_handler([this, &connection_mutex](
223 const nlohmann::json& slot_data) { 225 const nlohmann::json& slot_data) {
224 tracker_frame->SetStatusMessage("Connected to Archipelago!"); 226 tracker_frame->SetStatusMessage("Connected to Archipelago!");
225 wxLogStatus("Connected to Archipelago!"); 227 TrackerLog("Connected to Archipelago!");
226 228
227 data_storage_prefix = 229 data_storage_prefix =
228 "Lingo_" + std::to_string(apclient->get_player_number()) + "_"; 230 fmt::format("Lingo_{}_", apclient->get_player_number());
229 door_shuffle_mode = slot_data["shuffle_doors"].get<DoorShuffleMode>(); 231 door_shuffle_mode = slot_data["shuffle_doors"].get<DoorShuffleMode>();
230 color_shuffle = slot_data["shuffle_colors"].get<int>() == 1; 232 color_shuffle = slot_data["shuffle_colors"].get<int>() == 1;
231 painting_shuffle = slot_data["shuffle_paintings"].get<int>() == 1; 233 painting_shuffle = slot_data["shuffle_paintings"].get<int>() == 1;
@@ -277,18 +279,18 @@ struct APState {
277 corrected_keys.push_back(data_storage_prefix + key); 279 corrected_keys.push_back(data_storage_prefix + key);
278 } 280 }
279 281
280 { 282 victory_data_storage_key =
281 std::ostringstream vdsks; 283 fmt::format("_read_client_status_{}_{}", apclient->get_team_number(),
282 vdsks << "_read_client_status_" << apclient->get_team_number() << "_" 284 apclient->get_player_number());
283 << apclient->get_player_number();
284 victory_data_storage_key = vdsks.str();
285 }
286 285
287 corrected_keys.push_back(victory_data_storage_key); 286 corrected_keys.push_back(victory_data_storage_key);
288 287
289 apclient->Get(corrected_keys); 288 apclient->Get(corrected_keys);
290 apclient->SetNotify(corrected_keys); 289 apclient->SetNotify(corrected_keys);
291 290
291 ResetReachabilityRequirements();
292 RefreshTracker(true);
293
292 { 294 {
293 std::lock_guard connection_lock(connection_mutex); 295 std::lock_guard connection_lock(connection_mutex);
294 if (!has_connection_result) { 296 if (!has_connection_result) {
@@ -333,7 +335,7 @@ struct APState {
333 } 335 }
334 336
335 std::string full_message = hatkirby::implode(error_messages, " "); 337 std::string full_message = hatkirby::implode(error_messages, " ");
336 wxLogError(wxString(full_message)); 338 TrackerLog(full_message);
337 339
338 wxMessageBox(full_message, "Connection failed", wxOK | wxICON_ERROR); 340 wxMessageBox(full_message, "Connection failed", wxOK | wxICON_ERROR);
339 }); 341 });
@@ -355,7 +357,7 @@ struct APState {
355 DestroyClient(); 357 DestroyClient();
356 358
357 tracker_frame->SetStatusMessage("Disconnected from Archipelago."); 359 tracker_frame->SetStatusMessage("Disconnected from Archipelago.");
358 wxLogStatus("Timeout while connecting to Archipelago server."); 360 TrackerLog("Timeout while connecting to Archipelago server.");
359 wxMessageBox("Timeout while connecting to Archipelago server.", 361 wxMessageBox("Timeout while connecting to Archipelago server.",
360 "Connection failed", wxOK | wxICON_ERROR); 362 "Connection failed", wxOK | wxICON_ERROR);
361 363
@@ -374,9 +376,6 @@ struct APState {
374 } 376 }
375 377
376 if (connected) { 378 if (connected) {
377 ResetReachabilityRequirements();
378 RefreshTracker(true);
379 } else {
380 client_active = false; 379 client_active = false;
381 } 380 }
382 } 381 }
@@ -384,11 +383,12 @@ struct APState {
384 void HandleDataStorage(const std::string& key, const nlohmann::json& value) { 383 void HandleDataStorage(const std::string& key, const nlohmann::json& value) {
385 if (value.is_boolean()) { 384 if (value.is_boolean()) {
386 data_storage[key] = value.get<bool>(); 385 data_storage[key] = value.get<bool>();
387 wxLogVerbose("Data storage %s retrieved as %s", key, 386 TrackerLog(fmt::format("Data storage {} retrieved as {}", key,
388 (value.get<bool>() ? "true" : "false")); 387 (value.get<bool>() ? "true" : "false")));
389 } else if (value.is_number()) { 388 } else if (value.is_number()) {
390 data_storage[key] = value.get<int>(); 389 data_storage[key] = value.get<int>();
391 wxLogVerbose("Data storage %s retrieved as %d", key, value.get<int>()); 390 TrackerLog(fmt::format("Data storage {} retrieved as {}", key,
391 value.get<int>()));
392 } else if (value.is_object()) { 392 } else if (value.is_object()) {
393 if (key.ends_with("PlayerPos")) { 393 if (key.ends_with("PlayerPos")) {
394 auto map_value = value.get<std::map<std::string, int>>(); 394 auto map_value = value.get<std::map<std::string, int>>();
@@ -397,7 +397,7 @@ struct APState {
397 data_storage[key] = value.get<std::map<std::string, int>>(); 397 data_storage[key] = value.get<std::map<std::string, int>>();
398 } 398 }
399 399
400 wxLogVerbose("Data storage %s retrieved as dictionary", key); 400 TrackerLog(fmt::format("Data storage {} retrieved as dictionary", key));
401 } else if (value.is_null()) { 401 } else if (value.is_null()) {
402 if (key.ends_with("PlayerPos")) { 402 if (key.ends_with("PlayerPos")) {
403 player_pos = std::nullopt; 403 player_pos = std::nullopt;
@@ -405,7 +405,7 @@ struct APState {
405 data_storage.erase(key); 405 data_storage.erase(key);
406 } 406 }
407 407
408 wxLogVerbose("Data storage %s retrieved as null", key); 408 TrackerLog(fmt::format("Data storage {} retrieved as null", key));
409 } else if (value.is_array()) { 409 } else if (value.is_array()) {
410 auto list_value = value.get<std::vector<std::string>>(); 410 auto list_value = value.get<std::vector<std::string>>();
411 411
@@ -416,8 +416,8 @@ struct APState {
416 data_storage[key] = list_value; 416 data_storage[key] = list_value;
417 } 417 }
418 418
419 wxLogVerbose("Data storage %s retrieved as list: [%s]", key, 419 TrackerLog(fmt::format("Data storage {} retrieved as list: [{}]", key,
420 hatkirby::implode(list_value, ", ")); 420 hatkirby::implode(list_value, ", ")));
421 } 421 }
422 } 422 }
423 423
@@ -427,7 +427,7 @@ struct APState {
427 427
428 bool HasCheckedHuntPanel(int location_id) { 428 bool HasCheckedHuntPanel(int location_id) {
429 std::string key = 429 std::string key =
430 data_storage_prefix + "Hunt|" + std::to_string(location_id); 430 fmt::format("{}Hunt|{}", data_storage_prefix, location_id);
431 return data_storage.count(key) && std::any_cast<bool>(data_storage.at(key)); 431 return data_storage.count(key) && std::any_cast<bool>(data_storage.at(key));
432 } 432 }
433 433
@@ -436,12 +436,13 @@ struct APState {
436 } 436 }
437 437
438 bool HasAchievement(const std::string& name) { 438 bool HasAchievement(const std::string& name) {
439 std::string key = data_storage_prefix + "Achievement|" + name; 439 std::string key =
440 fmt::format("{}Achievement|{}", data_storage_prefix, name);
440 return data_storage.count(key) && std::any_cast<bool>(data_storage.at(key)); 441 return data_storage.count(key) && std::any_cast<bool>(data_storage.at(key));
441 } 442 }
442 443
443 const std::set<std::string>& GetCheckedPaintings() { 444 const std::set<std::string>& GetCheckedPaintings() {
444 std::string key = data_storage_prefix + "Paintings"; 445 std::string key = fmt::format("{}Paintings", data_storage_prefix);
445 if (!data_storage.count(key)) { 446 if (!data_storage.count(key)) {
446 data_storage[key] = std::set<std::string>(); 447 data_storage[key] = std::set<std::string>();
447 } 448 }
@@ -458,7 +459,7 @@ struct APState {
458 } 459 }
459 460
460 void RefreshTracker(bool reset) { 461 void RefreshTracker(bool reset) {
461 wxLogVerbose("Refreshing display..."); 462 TrackerLog("Refreshing display...");
462 463
463 RecalculateReachability(); 464 RecalculateReachability();
464 465
@@ -472,7 +473,7 @@ struct APState {
472 int64_t GetItemId(const std::string& item_name) { 473 int64_t GetItemId(const std::string& item_name) {
473 int64_t ap_id = apclient->get_item_id(item_name); 474 int64_t ap_id = apclient->get_item_id(item_name);
474 if (ap_id == APClient::INVALID_NAME_ID) { 475 if (ap_id == APClient::INVALID_NAME_ID) {
475 wxLogError("Could not find AP item ID for %s", item_name); 476 TrackerLog(fmt::format("Could not find AP item ID for {}", item_name));
476 } 477 }
477 478
478 return ap_id; 479 return ap_id;
diff --git a/src/game_data.cpp b/src/game_data.cpp index 85f7f51..77e435a 100644 --- a/src/game_data.cpp +++ b/src/game_data.cpp
@@ -1,11 +1,6 @@
1#include "game_data.h" 1#include "game_data.h"
2 2
3#include <wx/wxprec.h> 3#include <fmt/core.h>
4
5#ifndef WX_PRECOMP
6#include <wx/wx.h>
7#endif
8
9#include <hkutil/string.h> 4#include <hkutil/string.h>
10#include <yaml-cpp/yaml.h> 5#include <yaml-cpp/yaml.h>
11 6
@@ -13,6 +8,7 @@
13#include <sstream> 8#include <sstream>
14 9
15#include "global.h" 10#include "global.h"
11#include "logger.h"
16 12
17namespace { 13namespace {
18 14
@@ -36,7 +32,7 @@ LingoColor GetColorForString(const std::string &str) {
36 } else if (str == "purple") { 32 } else if (str == "purple") {
37 return LingoColor::kPurple; 33 return LingoColor::kPurple;
38 } else { 34 } else {
39 wxLogError("Invalid color: %s", str); 35 TrackerLog(fmt::format("Invalid color: {}", str));
40 36
41 return LingoColor::kNone; 37 return LingoColor::kNone;
42 } 38 }
@@ -88,7 +84,7 @@ struct GameData {
88 ap_id_by_color_[GetColorForString(input_name)] = 84 ap_id_by_color_[GetColorForString(input_name)] =
89 ids_config["special_items"][color_name].as<int>(); 85 ids_config["special_items"][color_name].as<int>();
90 } else { 86 } else {
91 wxLogError("Missing AP item ID for color %s", color_name); 87 TrackerLog(fmt::format("Missing AP item ID for color {}", color_name));
92 } 88 }
93 }; 89 };
94 90
@@ -165,7 +161,8 @@ struct GameData {
165 // This shouldn't happen. 161 // This shouldn't happen.
166 std::ostringstream formatted; 162 std::ostringstream formatted;
167 formatted << entrance_it; 163 formatted << entrance_it;
168 wxLogError("Error reading game data: %s", formatted.str()); 164 TrackerLog(
165 fmt::format("Error reading game data: {}", formatted.str()));
169 break; 166 break;
170 } 167 }
171 } 168 }
@@ -290,8 +287,9 @@ struct GameData {
290 [panels_[panel_id].name] 287 [panels_[panel_id].name]
291 .as<int>(); 288 .as<int>();
292 } else { 289 } else {
293 wxLogError("Missing AP location ID for panel %s - %s", 290 TrackerLog(fmt::format("Missing AP location ID for panel {} - {}",
294 rooms_[room_id].name, panels_[panel_id].name); 291 rooms_[room_id].name,
292 panels_[panel_id].name));
295 } 293 }
296 } 294 }
297 } 295 }
@@ -354,8 +352,9 @@ struct GameData {
354 [doors_[door_id].name]["item"] 352 [doors_[door_id].name]["item"]
355 .as<int>(); 353 .as<int>();
356 } else { 354 } else {
357 wxLogError("Missing AP item ID for door %s - %s", 355 TrackerLog(fmt::format("Missing AP item ID for door {} - {}",
358 rooms_[room_id].name, doors_[door_id].name); 356 rooms_[room_id].name,
357 doors_[door_id].name));
359 } 358 }
360 } 359 }
361 360
@@ -369,8 +368,8 @@ struct GameData {
369 ids_config["door_groups"][doors_[door_id].group_name] 368 ids_config["door_groups"][doors_[door_id].group_name]
370 .as<int>(); 369 .as<int>();
371 } else { 370 } else {
372 wxLogError("Missing AP item ID for door group %s", 371 TrackerLog(fmt::format("Missing AP item ID for door group {}",
373 doors_[door_id].group_name); 372 doors_[door_id].group_name));
374 } 373 }
375 } 374 }
376 375
@@ -380,11 +379,11 @@ struct GameData {
380 } else if (!door_it.second["skip_location"] && 379 } else if (!door_it.second["skip_location"] &&
381 !door_it.second["event"]) { 380 !door_it.second["event"]) {
382 if (has_external_panels) { 381 if (has_external_panels) {
383 wxLogError( 382 TrackerLog(fmt::format(
384 "%s - %s has panels from other rooms but does not have an " 383 "{} - {} has panels from other rooms but does not have an "
385 "explicit location name and is not marked skip_location or " 384 "explicit location name and is not marked skip_location or "
386 "event", 385 "event",
387 rooms_[room_id].name, doors_[door_id].name); 386 rooms_[room_id].name, doors_[door_id].name));
388 } 387 }
389 388
390 doors_[door_id].location_name = 389 doors_[door_id].location_name =
@@ -404,8 +403,9 @@ struct GameData {
404 [doors_[door_id].name]["location"] 403 [doors_[door_id].name]["location"]
405 .as<int>(); 404 .as<int>();
406 } else { 405 } else {
407 wxLogError("Missing AP location ID for door %s - %s", 406 TrackerLog(fmt::format("Missing AP location ID for door {} - {}",
408 rooms_[room_id].name, doors_[door_id].name); 407 rooms_[room_id].name,
408 doors_[door_id].name));
409 } 409 }
410 } 410 }
411 411
@@ -473,8 +473,8 @@ struct GameData {
473 progressive_item_id = 473 progressive_item_id =
474 ids_config["progression"][progressive_item_name].as<int>(); 474 ids_config["progression"][progressive_item_name].as<int>();
475 } else { 475 } else {
476 wxLogError("Missing AP item ID for progressive item %s", 476 TrackerLog(fmt::format("Missing AP item ID for progressive item {}",
477 progressive_item_name); 477 progressive_item_name));
478 } 478 }
479 479
480 int index = 1; 480 int index = 1;
@@ -553,14 +553,13 @@ struct GameData {
553 int area_id = AddOrGetArea(area_name); 553 int area_id = AddOrGetArea(area_name);
554 MapArea &map_area = map_areas_[area_id]; 554 MapArea &map_area = map_areas_[area_id];
555 // room field should be the original room ID 555 // room field should be the original room ID
556 map_area.locations.push_back( 556 map_area.locations.push_back({.name = section_name,
557 {.name = section_name, 557 .ap_location_name = location_name,
558 .ap_location_name = location_name, 558 .ap_location_id = panel.ap_location_id,
559 .ap_location_id = panel.ap_location_id, 559 .room = panel.room,
560 .room = panel.room, 560 .panels = {panel.id},
561 .panels = {panel.id}, 561 .classification = classification,
562 .classification = classification, 562 .hunt = panel.hunt});
563 .hunt = panel.hunt});
564 locations_by_name[location_name] = {area_id, 563 locations_by_name[location_name] = {area_id,
565 map_area.locations.size() - 1}; 564 map_area.locations.size() - 1};
566 } 565 }
@@ -638,7 +637,7 @@ struct GameData {
638 637
639 // Report errors. 638 // Report errors.
640 for (const std::string &area : malconfigured_areas_) { 639 for (const std::string &area : malconfigured_areas_) {
641 wxLogError("Area data not found for: %s", area); 640 TrackerLog(fmt::format("Area data not found for: {}", area));
642 } 641 }
643 642
644 // Read in subway items. 643 // Read in subway items.
@@ -709,7 +708,7 @@ struct GameData {
709 708
710 for (const auto &[tag, items] : subway_tags) { 709 for (const auto &[tag, items] : subway_tags) {
711 if (items.size() == 1) { 710 if (items.size() == 1) {
712 wxLogWarning("Singleton subway item tag: %s", tag); 711 TrackerLog(fmt::format("Singleton subway item tag: {}", tag));
713 } 712 }
714 } 713 }
715 } 714 }
diff --git a/src/logger.cpp b/src/logger.cpp new file mode 100644 index 0000000..09fc331 --- /dev/null +++ b/src/logger.cpp
@@ -0,0 +1,32 @@
1#include "logger.h"
2
3#include <chrono>
4#include <fstream>
5#include <mutex>
6
7#include "global.h"
8
9namespace {
10
11class Logger {
12 public:
13 Logger() : logfile_(GetAbsolutePath("debug.log")) {}
14
15 void LogLine(const std::string& text) {
16 std::lock_guard guard(file_mutex_);
17 logfile_ << "[" << std::chrono::system_clock::now() << "] " << text
18 << std::endl;
19 logfile_.flush();
20 }
21
22 private:
23 std::ofstream logfile_;
24 std::mutex file_mutex_;
25};
26
27} // namespace
28
29void TrackerLog(std::string text) {
30 static Logger* instance = new Logger();
31 instance->LogLine(text);
32}
diff --git a/src/logger.h b/src/logger.h new file mode 100644 index 0000000..a27839f --- /dev/null +++ b/src/logger.h
@@ -0,0 +1,8 @@
1#ifndef LOGGER_H_9BDD07EA
2#define LOGGER_H_9BDD07EA
3
4#include <string>
5
6void TrackerLog(std::string message);
7
8#endif /* end of include guard: LOGGER_H_9BDD07EA */
diff --git a/src/main.cpp b/src/main.cpp index b327b25..1d7cc9e 100644 --- a/src/main.cpp +++ b/src/main.cpp
@@ -4,25 +4,13 @@
4#include <wx/wx.h> 4#include <wx/wx.h>
5#endif 5#endif
6 6
7#include <fstream>
8
9#include "global.h" 7#include "global.h"
10#include "tracker_config.h" 8#include "tracker_config.h"
11#include "tracker_frame.h" 9#include "tracker_frame.h"
12 10
13static std::ofstream* logfile;
14
15class TrackerApp : public wxApp { 11class TrackerApp : public wxApp {
16 public: 12 public:
17 virtual bool OnInit() { 13 virtual bool OnInit() {
18 logfile = new std::ofstream(GetAbsolutePath("debug.log"));
19 wxLog::SetActiveTarget(new wxLogStream(logfile));
20 wxLog::SetVerbose(true);
21
22#ifndef NDEBUG
23 wxLog::SetActiveTarget(new wxLogWindow(nullptr, "Debug Log"));
24#endif
25
26 GetTrackerConfig().Load(); 14 GetTrackerConfig().Load();
27 15
28 TrackerFrame *frame = new TrackerFrame(); 16 TrackerFrame *frame = new TrackerFrame();
diff --git a/src/subway_map.cpp b/src/subway_map.cpp index 5c99567..c7b2c8a 100644 --- a/src/subway_map.cpp +++ b/src/subway_map.cpp
@@ -3,6 +3,7 @@
3#include <wx/dcbuffer.h> 3#include <wx/dcbuffer.h>
4#include <wx/dcgraph.h> 4#include <wx/dcgraph.h>
5 5
6#include <fmt/core.h>
6#include <sstream> 7#include <sstream>
7 8
8#include "ap_state.h" 9#include "ap_state.h"
@@ -85,10 +86,8 @@ void SubwayMap::OnConnect() {
85 86
86 if (!AP_IsSunwarpShuffle() && subway_item.sunwarp && 87 if (!AP_IsSunwarpShuffle() && subway_item.sunwarp &&
87 subway_item.sunwarp->type != SubwaySunwarpType::kFinal) { 88 subway_item.sunwarp->type != SubwaySunwarpType::kFinal) {
88 std::ostringstream tag; 89 std::string tag = fmt::format("subway{}", subway_item.sunwarp->dots);
89 tag << "sunwarp" << subway_item.sunwarp->dots; 90 tagged[tag].push_back(subway_item.id);
90
91 tagged[tag.str()].push_back(subway_item.id);
92 } 91 }
93 92
94 if (!AP_IsPilgrimageEnabled() && 93 if (!AP_IsPilgrimageEnabled() &&
@@ -100,8 +99,7 @@ void SubwayMap::OnConnect() {
100 99
101 if (AP_IsSunwarpShuffle()) { 100 if (AP_IsSunwarpShuffle()) {
102 for (const auto &[index, mapping] : AP_GetSunwarpMapping()) { 101 for (const auto &[index, mapping] : AP_GetSunwarpMapping()) {
103 std::ostringstream tag; 102 std::string tag = fmt::format("sunwarp{}", mapping.dots);
104 tag << "sunwarp" << mapping.dots;
105 103
106 SubwaySunwarp fromWarp; 104 SubwaySunwarp fromWarp;
107 if (index < 6) { 105 if (index < 6) {
@@ -121,8 +119,8 @@ void SubwayMap::OnConnect() {
121 toWarp.type = SubwaySunwarpType::kExit; 119 toWarp.type = SubwaySunwarpType::kExit;
122 } 120 }
123 121
124 tagged[tag.str()].push_back(GD_GetSubwayItemForSunwarp(fromWarp)); 122 tagged[tag].push_back(GD_GetSubwayItemForSunwarp(fromWarp));
125 tagged[tag.str()].push_back(GD_GetSubwayItemForSunwarp(toWarp)); 123 tagged[tag].push_back(GD_GetSubwayItemForSunwarp(toWarp));
126 } 124 }
127 } 125 }
128 126
diff --git a/src/version.h b/src/version.h index 7aab91b..060d557 100644 --- a/src/version.h +++ b/src/version.h
@@ -1,9 +1,10 @@
1#ifndef VERSION_H_C757E53C 1#ifndef VERSION_H_C757E53C
2#define VERSION_H_C757E53C 2#define VERSION_H_C757E53C
3 3
4#include <sstream>
5#include <regex> 4#include <regex>
6 5
6#include <fmt/core.h>
7
7struct Version { 8struct Version {
8 int major = 0; 9 int major = 0;
9 int minor = 0; 10 int minor = 0;
@@ -24,9 +25,7 @@ struct Version {
24 } 25 }
25 26
26 std::string ToString() const { 27 std::string ToString() const {
27 std::ostringstream output; 28 return fmt::format("v{}.{}.{}", major, minor, revision);
28 output << "v" << major << "." << minor << "." << revision;
29 return output.str();
30 } 29 }
31 30
32 bool operator<(const Version& rhs) const { 31 bool operator<(const Version& rhs) const {
diff --git a/vcpkg.json b/vcpkg.json index 925212a..e13d228 100644 --- a/vcpkg.json +++ b/vcpkg.json
@@ -3,6 +3,7 @@
3 "websocketpp", 3 "websocketpp",
4 "wxwidgets", 4 "wxwidgets",
5 "openssl", 5 "openssl",
6 "yaml-cpp" 6 "yaml-cpp",
7 "fmt"
7 ] 8 ]
8} 9}