#include "aoapplication.h" #include "courtroom.h" #include "debug_functions.h" #include "lobby.h" #include "networkmanager.h" #include "options.h" #include "widgets/aooptionsdialog.h" static QtMessageHandler original_message_handler; static AOApplication *message_handler_context; void message_handler(QtMsgType type, const QMessageLogContext &context, const QString &msg) { Q_EMIT message_handler_context->qt_log_message(type, context, msg); original_message_handler(type, context, msg); } AOApplication::AOApplication(QObject *parent) : QObject(parent) { net_manager = new NetworkManager(this); discord = new AttorneyOnline::Discord(); asset_lookup_cache.reserve(2048); message_handler_context = this; original_message_handler = qInstallMessageHandler(message_handler); mus_decoders[0] = ma_decoding_backend_libopus; mus_decoders[1] = ma_decoding_backend_libvorbis; mus_decoder_config = ma_decoder_config_init_default(); mus_decoder_config.pCustomBackendUserData = nullptr; mus_decoder_config.customBackendCount = 2; mus_decoder_config.ppCustomBackendVTables = mus_decoders; } AOApplication::~AOApplication() { destruct_lobby(); destruct_courtroom(); delete discord; qInstallMessageHandler(original_message_handler); } bool AOApplication::is_lobby_constructed() { return w_lobby; } void AOApplication::construct_lobby() { if (is_lobby_constructed()) { qWarning() << "lobby was attempted constructed when it already exists"; return; } w_lobby = new Lobby(this, net_manager); centerOrMoveWidgetOnPrimaryScreen(w_lobby); if (Options::getInstance().discordEnabled()) { discord->state_lobby(); } w_lobby->show(); } void AOApplication::destruct_lobby() { if (!is_lobby_constructed()) { qWarning() << "lobby was attempted destructed when it did not exist"; return; } delete w_lobby; w_lobby = nullptr; } bool AOApplication::is_courtroom_constructed() { return w_courtroom; } void AOApplication::construct_courtroom() { if (is_courtroom_constructed()) { qWarning() << "courtroom was attempted constructed when it already exists"; return; } w_courtroom = new Courtroom(this); centerOrMoveWidgetOnPrimaryScreen(w_courtroom); if (demo_server != nullptr) { QObject::connect(demo_server, &DemoServer::skip_timers, w_courtroom, &Courtroom::skip_clocks); } else { qWarning() << "demo server did not exist during courtroom construction"; } } void AOApplication::destruct_courtroom() { if (!is_courtroom_constructed()) { qWarning() << "courtroom was attempted destructed when it did not exist"; return; } delete demo_server; demo_server = nullptr; delete w_courtroom; w_courtroom = nullptr; } QString AOApplication::get_version_string() { return QString::number(RELEASE) + "." + QString::number(MAJOR_VERSION) + "." + QString::number(MINOR_VERSION); } QString AOApplication::get_revision_string() { return "1176bb5f 2026-02-06"; } QString AOApplication::get_sof_version_string() { return "SoF-6"; } QString AOApplication::find_image(QStringList p_list) { QString image_path; for (const QString &path : p_list) { if (file_exists(path)) { image_path = path; break; } } return image_path; } void AOApplication::server_disconnected() { if (is_courtroom_constructed()) { if (w_courtroom->isVisible()) { call_notice(tr("Disconnected from server.")); } construct_lobby(); destruct_courtroom(); } Options::getInstance().setServerSubTheme(QString()); } void AOApplication::loading_cancelled() { destruct_courtroom(); } void AOApplication::call_settings_menu() { AOOptionsDialog *l_dialog = new AOOptionsDialog(this); if (is_courtroom_constructed()) { connect(l_dialog, &AOOptionsDialog::reloadThemeRequest, w_courtroom, &Courtroom::on_reload_theme_clicked); } if (is_lobby_constructed()) {} l_dialog->exec(); if (is_courtroom_constructed()) { w_courtroom->playerList()->reloadPlayers(); } delete l_dialog; } void AOApplication::server_connected() { qInfo() << "Established connection to server."; destruct_courtroom(); construct_courtroom(); courtroom_loaded = false; } void AOApplication::initAudio() { ma_context ctx; if (ma_context_init(nullptr, 0, nullptr, &ctx) != MA_SUCCESS) { qCritical("Failed to initialize audio context."); } // TODO: Support multiple devices ma_resource_manager_config rm_config = ma_resource_manager_config_init(); rm_config.decodedFormat = ma_format_f32; rm_config.decodedChannels = 2; rm_config.decodedSampleRate = 48000; ma_decoding_backend_vtable *decoders[] = {ma_decoding_backend_libopus, ma_decoding_backend_libvorbis}; rm_config.ppCustomDecodingBackendVTables = decoders; rm_config.customDecodingBackendCount = sizeof(decoders) / sizeof(decoders[0]); rm_config.pCustomDecodingBackendUserData = nullptr; if (ma_resource_manager_init(&rm_config, &audio_rm) != MA_SUCCESS) { qCritical("Failed to initialize audio resource manager."); } ma_engine_config engine_config = ma_engine_config_init(); engine_config.pResourceManager = &audio_rm; if (ma_engine_init(&engine_config, &audio_engine) != MA_SUCCESS) { qCritical("Failed to initialize audio engine."); } } bool AOApplication::pointExistsOnScreen(QPoint point) { for (QScreen *screen : QApplication::screens()) { if (screen->availableGeometry().contains(point)) { return true; } } return false; } void AOApplication::centerOrMoveWidgetOnPrimaryScreen(QWidget *widget) { auto point = Options::getInstance().windowPosition(widget->objectName()); if (!Options::getInstance().restoreWindowPositionEnabled() || !point.has_value() || !pointExistsOnScreen(point.value())) { QRect geometry = QGuiApplication::primaryScreen()->geometry(); int x = (geometry.width() - widget->width()) / 2; int y = (geometry.height() - widget->height()) / 2; widget->move(x, y); } else { widget->move(point->x(), point->y()); } }