diff options
| author | Star Rauchenberger <fefferburbia@gmail.com> | 2024-05-14 12:53:59 -0400 |
|---|---|---|
| committer | Star Rauchenberger <fefferburbia@gmail.com> | 2024-05-14 12:53:59 -0400 |
| commit | bee4194f9e12c9d2210a5ecba7249bdfe3f3deda (patch) | |
| tree | 1212b2f05cea09e4fbf8f1a3c57418fb3e92fc36 | |
| parent | dff1d7382f2af91e50561bfdb9eb83773ac7c010 (diff) | |
| download | lingo-ap-tracker-bee4194f9e12c9d2210a5ecba7249bdfe3f3deda.tar.gz lingo-ap-tracker-bee4194f9e12c9d2210a5ecba7249bdfe3f3deda.tar.bz2 lingo-ap-tracker-bee4194f9e12c9d2210a5ecba7249bdfe3f3deda.zip | |
Switch to wx logging
| -rw-r--r-- | src/ap_state.cpp | 43 | ||||
| -rw-r--r-- | src/game_data.cpp | 59 | ||||
| -rw-r--r-- | src/logger.cpp | 39 | ||||
| -rw-r--r-- | src/logger.h | 25 | ||||
| -rw-r--r-- | src/main.cpp | 3 |
5 files changed, 85 insertions, 84 deletions
| diff --git a/src/ap_state.cpp b/src/ap_state.cpp index b057beb..e5ff74d 100644 --- a/src/ap_state.cpp +++ b/src/ap_state.cpp | |||
| @@ -75,7 +75,7 @@ struct APState { | |||
| 75 | 75 | ||
| 76 | void Connect(std::string server, std::string player, std::string password) { | 76 | void Connect(std::string server, std::string player, std::string password) { |
| 77 | if (!initialized) { | 77 | if (!initialized) { |
| 78 | TrackerLog("Initializing APState..."); | 78 | wxLogMessage("Initializing APState..."); |
| 79 | 79 | ||
| 80 | std::thread([this]() { | 80 | std::thread([this]() { |
| 81 | for (;;) { | 81 | for (;;) { |
| @@ -108,10 +108,10 @@ struct APState { | |||
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | tracker_frame->SetStatusMessage("Connecting to Archipelago server...."); | 110 | tracker_frame->SetStatusMessage("Connecting to Archipelago server...."); |
| 111 | TrackerLog("Connecting to Archipelago server (" + server + ")..."); | 111 | wxLogMessage("Connecting to Archipelago server (%s)...", server); |
| 112 | 112 | ||
| 113 | { | 113 | { |
| 114 | TrackerLog("Destroying old AP client..."); | 114 | wxLogMessage("Destroying old AP client..."); |
| 115 | 115 | ||
| 116 | std::lock_guard client_guard(client_mutex); | 116 | std::lock_guard client_guard(client_mutex); |
| 117 | 117 | ||
| @@ -155,10 +155,10 @@ struct APState { | |||
| 155 | apclient->set_room_info_handler([this, player, password]() { | 155 | apclient->set_room_info_handler([this, player, password]() { |
| 156 | inventory.clear(); | 156 | inventory.clear(); |
| 157 | 157 | ||
| 158 | TrackerLog("Connected to Archipelago server. Authenticating as " + | 158 | wxLogMessage("Connected to Archipelago server. Authenticating as %s %s", |
| 159 | player + | 159 | player, |
| 160 | (password.empty() ? " without password" | 160 | (password.empty() ? " without password" |
| 161 | : " with password " + password)); | 161 | : " with password " + password)); |
| 162 | tracker_frame->SetStatusMessage( | 162 | tracker_frame->SetStatusMessage( |
| 163 | "Connected to Archipelago server. Authenticating..."); | 163 | "Connected to Archipelago server. Authenticating..."); |
| 164 | 164 | ||
| @@ -170,7 +170,7 @@ struct APState { | |||
| 170 | [this](const std::list<int64_t>& locations) { | 170 | [this](const std::list<int64_t>& locations) { |
| 171 | for (const int64_t location_id : locations) { | 171 | for (const int64_t location_id : locations) { |
| 172 | checked_locations.insert(location_id); | 172 | checked_locations.insert(location_id); |
| 173 | TrackerLog("Location: " + std::to_string(location_id)); | 173 | wxLogMessage("Location: %lld", location_id); |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | RefreshTracker(false); | 176 | RefreshTracker(false); |
| @@ -179,14 +179,14 @@ struct APState { | |||
| 179 | apclient->set_slot_disconnected_handler([this]() { | 179 | apclient->set_slot_disconnected_handler([this]() { |
| 180 | tracker_frame->SetStatusMessage( | 180 | tracker_frame->SetStatusMessage( |
| 181 | "Disconnected from Archipelago. Attempting to reconnect..."); | 181 | "Disconnected from Archipelago. Attempting to reconnect..."); |
| 182 | TrackerLog( | 182 | wxLogMessage( |
| 183 | "Slot disconnected from Archipelago. Attempting to reconnect..."); | 183 | "Slot disconnected from Archipelago. Attempting to reconnect..."); |
| 184 | }); | 184 | }); |
| 185 | 185 | ||
| 186 | apclient->set_socket_disconnected_handler([this]() { | 186 | apclient->set_socket_disconnected_handler([this]() { |
| 187 | tracker_frame->SetStatusMessage( | 187 | tracker_frame->SetStatusMessage( |
| 188 | "Disconnected from Archipelago. Attempting to reconnect..."); | 188 | "Disconnected from Archipelago. Attempting to reconnect..."); |
| 189 | TrackerLog( | 189 | wxLogMessage( |
| 190 | "Socket disconnected from Archipelago. Attempting to reconnect..."); | 190 | "Socket disconnected from Archipelago. Attempting to reconnect..."); |
| 191 | }); | 191 | }); |
| 192 | 192 | ||
| @@ -194,7 +194,7 @@ struct APState { | |||
| 194 | [this](const std::list<APClient::NetworkItem>& items) { | 194 | [this](const std::list<APClient::NetworkItem>& items) { |
| 195 | for (const APClient::NetworkItem& item : items) { | 195 | for (const APClient::NetworkItem& item : items) { |
| 196 | inventory[item.item]++; | 196 | inventory[item.item]++; |
| 197 | TrackerLog("Item: " + std::to_string(item.item)); | 197 | wxLogMessage("Item: %lld", item.item); |
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | RefreshTracker(false); | 200 | RefreshTracker(false); |
| @@ -219,7 +219,7 @@ struct APState { | |||
| 219 | apclient->set_slot_connected_handler([this]( | 219 | apclient->set_slot_connected_handler([this]( |
| 220 | const nlohmann::json& slot_data) { | 220 | const nlohmann::json& slot_data) { |
| 221 | tracker_frame->SetStatusMessage("Connected to Archipelago!"); | 221 | tracker_frame->SetStatusMessage("Connected to Archipelago!"); |
| 222 | TrackerLog("Connected to Archipelago!"); | 222 | wxLogMessage("Connected to Archipelago!"); |
| 223 | 223 | ||
| 224 | data_storage_prefix = | 224 | data_storage_prefix = |
| 225 | "Lingo_" + std::to_string(apclient->get_player_number()) + "_"; | 225 | "Lingo_" + std::to_string(apclient->get_player_number()) + "_"; |
| @@ -323,7 +323,7 @@ struct APState { | |||
| 323 | } | 323 | } |
| 324 | 324 | ||
| 325 | std::string full_message = hatkirby::implode(error_messages, " "); | 325 | std::string full_message = hatkirby::implode(error_messages, " "); |
| 326 | TrackerLog(full_message); | 326 | wxLogError(wxString(full_message)); |
| 327 | 327 | ||
| 328 | wxMessageBox(full_message, "Connection failed", wxOK | wxICON_ERROR); | 328 | wxMessageBox(full_message, "Connection failed", wxOK | wxICON_ERROR); |
| 329 | }); | 329 | }); |
| @@ -342,7 +342,7 @@ struct APState { | |||
| 342 | 342 | ||
| 343 | tracker_frame->SetStatusMessage("Disconnected from Archipelago."); | 343 | tracker_frame->SetStatusMessage("Disconnected from Archipelago."); |
| 344 | 344 | ||
| 345 | TrackerLog("Timeout while connecting to Archipelago server."); | 345 | wxLogMessage("Timeout while connecting to Archipelago server."); |
| 346 | wxMessageBox("Timeout while connecting to Archipelago server.", | 346 | wxMessageBox("Timeout while connecting to Archipelago server.", |
| 347 | "Connection failed", wxOK | wxICON_ERROR); | 347 | "Connection failed", wxOK | wxICON_ERROR); |
| 348 | } | 348 | } |
| @@ -362,12 +362,11 @@ struct APState { | |||
| 362 | void HandleDataStorage(const std::string& key, const nlohmann::json& value) { | 362 | void HandleDataStorage(const std::string& key, const nlohmann::json& value) { |
| 363 | if (value.is_boolean()) { | 363 | if (value.is_boolean()) { |
| 364 | data_storage[key] = value.get<bool>(); | 364 | data_storage[key] = value.get<bool>(); |
| 365 | TrackerLog("Data storage " + key + " retrieved as " + | 365 | wxLogMessage("Data storage %s retrieved as %s", key, |
| 366 | (value.get<bool>() ? "true" : "false")); | 366 | (value.get<bool>() ? "true" : "false")); |
| 367 | } else if (value.is_number()) { | 367 | } else if (value.is_number()) { |
| 368 | data_storage[key] = value.get<int>(); | 368 | data_storage[key] = value.get<int>(); |
| 369 | TrackerLog("Data storage " + key + " retrieved as " + | 369 | wxLogMessage("Data storage %s retrieved as %d", key, value.get<int>()); |
| 370 | std::to_string(value.get<int>())); | ||
| 371 | } else if (value.is_object()) { | 370 | } else if (value.is_object()) { |
| 372 | if (key.ends_with("PlayerPos")) { | 371 | if (key.ends_with("PlayerPos")) { |
| 373 | auto map_value = value.get<std::map<std::string, int>>(); | 372 | auto map_value = value.get<std::map<std::string, int>>(); |
| @@ -376,7 +375,7 @@ struct APState { | |||
| 376 | data_storage[key] = value.get<std::map<std::string, int>>(); | 375 | data_storage[key] = value.get<std::map<std::string, int>>(); |
| 377 | } | 376 | } |
| 378 | 377 | ||
| 379 | TrackerLog("Data storage " + key + " retrieved as dictionary"); | 378 | wxLogMessage("Data storage %s retrieved as dictionary", key); |
| 380 | } else if (value.is_null()) { | 379 | } else if (value.is_null()) { |
| 381 | if (key.ends_with("PlayerPos")) { | 380 | if (key.ends_with("PlayerPos")) { |
| 382 | player_pos = std::nullopt; | 381 | player_pos = std::nullopt; |
| @@ -384,7 +383,7 @@ struct APState { | |||
| 384 | data_storage.erase(key); | 383 | data_storage.erase(key); |
| 385 | } | 384 | } |
| 386 | 385 | ||
| 387 | TrackerLog("Data storage " + key + " retrieved as null"); | 386 | wxLogMessage("Data storage %s retrieved as null", key); |
| 388 | } | 387 | } |
| 389 | } | 388 | } |
| 390 | 389 | ||
| @@ -408,7 +407,7 @@ struct APState { | |||
| 408 | } | 407 | } |
| 409 | 408 | ||
| 410 | void RefreshTracker(bool reset) { | 409 | void RefreshTracker(bool reset) { |
| 411 | TrackerLog("Refreshing display..."); | 410 | wxLogMessage("Refreshing display..."); |
| 412 | 411 | ||
| 413 | RecalculateReachability(); | 412 | RecalculateReachability(); |
| 414 | 413 | ||
| @@ -422,7 +421,7 @@ struct APState { | |||
| 422 | int64_t GetItemId(const std::string& item_name) { | 421 | int64_t GetItemId(const std::string& item_name) { |
| 423 | int64_t ap_id = apclient->get_item_id(item_name); | 422 | int64_t ap_id = apclient->get_item_id(item_name); |
| 424 | if (ap_id == APClient::INVALID_NAME_ID) { | 423 | if (ap_id == APClient::INVALID_NAME_ID) { |
| 425 | TrackerLog("Could not find AP item ID for " + item_name); | 424 | wxLogError("Could not find AP item ID for %s", item_name); |
| 426 | } | 425 | } |
| 427 | 426 | ||
| 428 | return ap_id; | 427 | return ap_id; |
| diff --git a/src/game_data.cpp b/src/game_data.cpp index 74f872c..7bc3134 100644 --- a/src/game_data.cpp +++ b/src/game_data.cpp | |||
| @@ -31,9 +31,7 @@ LingoColor GetColorForString(const std::string &str) { | |||
| 31 | } else if (str == "purple") { | 31 | } else if (str == "purple") { |
| 32 | return LingoColor::kPurple; | 32 | return LingoColor::kPurple; |
| 33 | } else { | 33 | } else { |
| 34 | std::ostringstream errmsg; | 34 | wxLogError("Invalid color: %s", str); |
| 35 | errmsg << "Invalid color: " << str; | ||
| 36 | TrackerLog(errmsg.str()); | ||
| 37 | 35 | ||
| 38 | return LingoColor::kNone; | 36 | return LingoColor::kNone; |
| 39 | } | 37 | } |
| @@ -83,9 +81,7 @@ struct GameData { | |||
| 83 | ap_id_by_color_[GetColorForString(input_name)] = | 81 | ap_id_by_color_[GetColorForString(input_name)] = |
| 84 | ids_config["special_items"][color_name].as<int>(); | 82 | ids_config["special_items"][color_name].as<int>(); |
| 85 | } else { | 83 | } else { |
| 86 | std::ostringstream errmsg; | 84 | wxLogError("Missing AP item ID for color %s", color_name); |
| 87 | errmsg << "Missing AP item ID for color " << color_name; | ||
| 88 | TrackerLog(errmsg.str()); | ||
| 89 | } | 85 | } |
| 90 | }; | 86 | }; |
| 91 | 87 | ||
| @@ -160,8 +156,9 @@ struct GameData { | |||
| 160 | } | 156 | } |
| 161 | default: { | 157 | default: { |
| 162 | // This shouldn't happen. | 158 | // This shouldn't happen. |
| 163 | std::cout << "Error reading game data: " << entrance_it | 159 | std::ostringstream formatted; |
| 164 | << std::endl; | 160 | formatted << entrance_it; |
| 161 | wxLogError("Error reading game data: %s", formatted.str()); | ||
| 165 | break; | 162 | break; |
| 166 | } | 163 | } |
| 167 | } | 164 | } |
| @@ -281,10 +278,8 @@ struct GameData { | |||
| 281 | [panels_[panel_id].name] | 278 | [panels_[panel_id].name] |
| 282 | .as<int>(); | 279 | .as<int>(); |
| 283 | } else { | 280 | } else { |
| 284 | std::ostringstream errmsg; | 281 | wxLogError("Missing AP location ID for panel %s - %s", |
| 285 | errmsg << "Missing AP location ID for panel " | 282 | rooms_[room_id].name, panels_[panel_id].name); |
| 286 | << rooms_[room_id].name << " - " << panels_[panel_id].name; | ||
| 287 | TrackerLog(errmsg.str()); | ||
| 288 | } | 283 | } |
| 289 | } | 284 | } |
| 290 | } | 285 | } |
| @@ -347,10 +342,8 @@ struct GameData { | |||
| 347 | [doors_[door_id].name]["item"] | 342 | [doors_[door_id].name]["item"] |
| 348 | .as<int>(); | 343 | .as<int>(); |
| 349 | } else { | 344 | } else { |
| 350 | std::ostringstream errmsg; | 345 | wxLogError("Missing AP item ID for door %s - %s", |
| 351 | errmsg << "Missing AP item ID for door " << rooms_[room_id].name | 346 | rooms_[room_id].name, doors_[door_id].name); |
| 352 | << " - " << doors_[door_id].name; | ||
| 353 | TrackerLog(errmsg.str()); | ||
| 354 | } | 347 | } |
| 355 | } | 348 | } |
| 356 | 349 | ||
| @@ -364,10 +357,8 @@ struct GameData { | |||
| 364 | ids_config["door_groups"][doors_[door_id].group_name] | 357 | ids_config["door_groups"][doors_[door_id].group_name] |
| 365 | .as<int>(); | 358 | .as<int>(); |
| 366 | } else { | 359 | } else { |
| 367 | std::ostringstream errmsg; | 360 | wxLogError("Missing AP item ID for door group %s", |
| 368 | errmsg << "Missing AP item ID for door group " | 361 | doors_[door_id].group_name); |
| 369 | << doors_[door_id].group_name; | ||
| 370 | TrackerLog(errmsg.str()); | ||
| 371 | } | 362 | } |
| 372 | } | 363 | } |
| 373 | 364 | ||
| @@ -377,13 +368,11 @@ struct GameData { | |||
| 377 | } else if (!door_it.second["skip_location"] && | 368 | } else if (!door_it.second["skip_location"] && |
| 378 | !door_it.second["event"]) { | 369 | !door_it.second["event"]) { |
| 379 | if (has_external_panels) { | 370 | if (has_external_panels) { |
| 380 | std::ostringstream errmsg; | 371 | wxLogError( |
| 381 | errmsg | 372 | "%s - %s has panels from other rooms but does not have an " |
| 382 | << rooms_[room_id].name << " - " << doors_[door_id].name | 373 | "explicit location name and is not marked skip_location or " |
| 383 | << " has panels from other rooms but does not have an " | 374 | "event", |
| 384 | "explicit " | 375 | rooms_[room_id].name, doors_[door_id].name); |
| 385 | "location name and is not marked skip_location or event"; | ||
| 386 | TrackerLog(errmsg.str()); | ||
| 387 | } | 376 | } |
| 388 | 377 | ||
| 389 | doors_[door_id].location_name = | 378 | doors_[door_id].location_name = |
| @@ -403,10 +392,8 @@ struct GameData { | |||
| 403 | [doors_[door_id].name]["location"] | 392 | [doors_[door_id].name]["location"] |
| 404 | .as<int>(); | 393 | .as<int>(); |
| 405 | } else { | 394 | } else { |
| 406 | std::ostringstream errmsg; | 395 | wxLogError("Missing AP location ID for door %s - %s", |
| 407 | errmsg << "Missing AP location ID for door " | 396 | rooms_[room_id].name, doors_[door_id].name); |
| 408 | << rooms_[room_id].name << " - " << doors_[door_id].name; | ||
| 409 | TrackerLog(errmsg.str()); | ||
| 410 | } | 397 | } |
| 411 | } | 398 | } |
| 412 | 399 | ||
| @@ -472,10 +459,8 @@ struct GameData { | |||
| 472 | progressive_item_id = | 459 | progressive_item_id = |
| 473 | ids_config["progression"][progressive_item_name].as<int>(); | 460 | ids_config["progression"][progressive_item_name].as<int>(); |
| 474 | } else { | 461 | } else { |
| 475 | std::ostringstream errmsg; | 462 | wxLogError("Missing AP item ID for progressive item %s", |
| 476 | errmsg << "Missing AP item ID for progressive item " | 463 | progressive_item_name); |
| 477 | << progressive_item_name; | ||
| 478 | TrackerLog(errmsg.str()); | ||
| 479 | } | 464 | } |
| 480 | 465 | ||
| 481 | int index = 1; | 466 | int index = 1; |
| @@ -606,9 +591,7 @@ struct GameData { | |||
| 606 | 591 | ||
| 607 | // Report errors. | 592 | // Report errors. |
| 608 | for (const std::string &area : malconfigured_areas_) { | 593 | for (const std::string &area : malconfigured_areas_) { |
| 609 | std::ostringstream errstr; | 594 | wxLogError("Area data not found for: %s", area); |
| 610 | errstr << "Area data not found for: " << area; | ||
| 611 | TrackerLog(errstr.str()); | ||
| 612 | } | 595 | } |
| 613 | 596 | ||
| 614 | // Read in subway items. | 597 | // Read in subway items. |
| diff --git a/src/logger.cpp b/src/logger.cpp index 4b722c8..dddcc4a 100644 --- a/src/logger.cpp +++ b/src/logger.cpp | |||
| @@ -1,32 +1,27 @@ | |||
| 1 | #include "logger.h" | 1 | #include "logger.h" |
| 2 | 2 | ||
| 3 | #include <chrono> | ||
| 4 | #include <fstream> | ||
| 5 | #include <mutex> | ||
| 6 | |||
| 7 | #include "global.h" | 3 | #include "global.h" |
| 8 | 4 | ||
| 9 | namespace { | 5 | Logger::Logger() : logfile_(GetAbsolutePath("debug.log")) {} |
| 10 | 6 | ||
| 11 | class Logger { | 7 | void Logger::Flush() { |
| 12 | public: | 8 | wxLog::Flush(); |
| 13 | Logger() : logfile_(GetAbsolutePath("debug.log")) {} | ||
| 14 | 9 | ||
| 15 | void LogLine(const std::string& text) { | 10 | std::lock_guard guard(file_mutex_); |
| 16 | std::lock_guard guard(file_mutex_); | 11 | logfile_.flush(); |
| 17 | logfile_ << "[" << std::chrono::system_clock::now() << "] " << text | 12 | } |
| 18 | << std::endl; | ||
| 19 | logfile_.flush(); | ||
| 20 | } | ||
| 21 | 13 | ||
| 22 | private: | 14 | Logger::~Logger() { |
| 23 | std::ofstream logfile_; | 15 | std::lock_guard guard(file_mutex_); |
| 24 | std::mutex file_mutex_; | 16 | logfile_.flush(); |
| 25 | }; | 17 | } |
| 26 | 18 | ||
| 27 | } // namespace | 19 | void Logger::DoLogText(const wxString& msg) { |
| 20 | #ifdef _WIN64 | ||
| 21 | OutputDebugStringA(msg.c_str()); | ||
| 22 | OutputDebugStringA("\r\n"); | ||
| 23 | #endif | ||
| 28 | 24 | ||
| 29 | void TrackerLog(const std::string& text) { | 25 | std::lock_guard guard(file_mutex_); |
| 30 | static Logger* instance = new Logger(); | 26 | logfile_ << msg << std::endl; |
| 31 | instance->LogLine(text); | ||
| 32 | } | 27 | } |
| diff --git a/src/logger.h b/src/logger.h index db9bb49..b1a1d99 100644 --- a/src/logger.h +++ b/src/logger.h | |||
| @@ -1,8 +1,29 @@ | |||
| 1 | #ifndef LOGGER_H_6E7B9594 | 1 | #ifndef LOGGER_H_6E7B9594 |
| 2 | #define LOGGER_H_6E7B9594 | 2 | #define LOGGER_H_6E7B9594 |
| 3 | 3 | ||
| 4 | #include <string> | 4 | #include <wx/wxprec.h> |
| 5 | 5 | ||
| 6 | void TrackerLog(const std::string& text); | 6 | #ifndef WX_PRECOMP |
| 7 | #include <wx/wx.h> | ||
| 8 | #endif | ||
| 9 | |||
| 10 | #include <fstream> | ||
| 11 | #include <mutex> | ||
| 12 | |||
| 13 | class Logger : public wxLog { | ||
| 14 | public: | ||
| 15 | Logger(); | ||
| 16 | |||
| 17 | void Flush() override; | ||
| 18 | |||
| 19 | ~Logger(); | ||
| 20 | |||
| 21 | protected: | ||
| 22 | void DoLogText(const wxString& msg) override; | ||
| 23 | |||
| 24 | private: | ||
| 25 | std::ofstream logfile_; | ||
| 26 | std::mutex file_mutex_; | ||
| 27 | }; | ||
| 7 | 28 | ||
| 8 | #endif /* end of include guard: LOGGER_H_6E7B9594 */ | 29 | #endif /* end of include guard: LOGGER_H_6E7B9594 */ |
| diff --git a/src/main.cpp b/src/main.cpp index fe9aceb..db7653c 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -4,12 +4,15 @@ | |||
| 4 | #include <wx/wx.h> | 4 | #include <wx/wx.h> |
| 5 | #endif | 5 | #endif |
| 6 | 6 | ||
| 7 | #include "logger.h" | ||
| 7 | #include "tracker_config.h" | 8 | #include "tracker_config.h" |
| 8 | #include "tracker_frame.h" | 9 | #include "tracker_frame.h" |
| 9 | 10 | ||
| 10 | class TrackerApp : public wxApp { | 11 | class TrackerApp : public wxApp { |
| 11 | public: | 12 | public: |
| 12 | virtual bool OnInit() { | 13 | virtual bool OnInit() { |
| 14 | wxLog::SetActiveTarget(new Logger()); | ||
| 15 | |||
| 13 | GetTrackerConfig().Load(); | 16 | GetTrackerConfig().Load(); |
| 14 | 17 | ||
| 15 | TrackerFrame *frame = new TrackerFrame(); | 18 | TrackerFrame *frame = new TrackerFrame(); |
