diff --git a/CMakeLists.txt b/CMakeLists.txt index ba09819..f3684f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,6 +77,12 @@ add_executable(Attorney_Online src/lobby.cpp src/lobby.h src/main.cpp + src/net/netconnection.cpp + src/net/netconnection.h + src/net/nettcpconnection.cpp + src/net/nettcpconnection.h + src/net/netwebsocketconnection.cpp + src/net/netwebsocketconnection.h src/networkmanager.cpp src/networkmanager.h src/options.cpp diff --git a/src/aoapplication.cpp b/src/aoapplication.cpp index edd241b..b0b90e2 100644 --- a/src/aoapplication.cpp +++ b/src/aoapplication.cpp @@ -40,16 +40,20 @@ AOApplication::~AOApplication() qInstallMessageHandler(original_message_handler); } +bool AOApplication::is_lobby_constructed() +{ + return w_lobby; +} + void AOApplication::construct_lobby() { - if (lobby_constructed) + if (is_lobby_constructed()) { qWarning() << "lobby was attempted constructed when it already exists"; return; } w_lobby = new Lobby(this, net_manager); - lobby_constructed = true; QRect geometry = QGuiApplication::primaryScreen()->geometry(); int x = (geometry.width() - w_lobby->width()) / 2; @@ -71,7 +75,7 @@ void AOApplication::construct_lobby() void AOApplication::destruct_lobby() { - if (!lobby_constructed) + if (!is_lobby_constructed()) { qWarning() << "lobby was attempted destructed when it did not exist"; return; @@ -79,19 +83,22 @@ void AOApplication::destruct_lobby() delete w_lobby; w_lobby = nullptr; - lobby_constructed = false; +} + +bool AOApplication::is_courtroom_constructed() +{ + return w_courtroom; } void AOApplication::construct_courtroom() { - if (courtroom_constructed) + if (is_courtroom_constructed()) { qWarning() << "courtroom was attempted constructed when it already exists"; return; } w_courtroom = new Courtroom(this); - courtroom_constructed = true; QRect geometry = QGuiApplication::primaryScreen()->geometry(); int x = (geometry.width() - w_courtroom->width()) / 2; @@ -110,7 +117,7 @@ void AOApplication::construct_courtroom() void AOApplication::destruct_courtroom() { - if (!courtroom_constructed) + if (!is_courtroom_constructed()) { qWarning() << "courtroom was attempted destructed when it did not exist"; return; @@ -118,7 +125,6 @@ void AOApplication::destruct_courtroom() delete w_courtroom; w_courtroom = nullptr; - courtroom_constructed = false; } QString AOApplication::get_version_string() @@ -128,9 +134,12 @@ QString AOApplication::get_version_string() void AOApplication::server_disconnected() { - if (courtroom_constructed) + if (is_courtroom_constructed()) { - call_notice(tr("Disconnected from server.")); + if (w_courtroom->isVisible()) + { + call_notice(tr("Disconnected from server.")); + } construct_lobby(); destruct_courtroom(); } @@ -145,12 +154,12 @@ void AOApplication::loading_cancelled() void AOApplication::call_settings_menu() { AOOptionsDialog *l_dialog = new AOOptionsDialog(this); - if (courtroom_constructed) + if (is_courtroom_constructed()) { connect(l_dialog, &AOOptionsDialog::reloadThemeRequest, w_courtroom, &Courtroom::on_reload_theme_clicked); } - if (lobby_constructed) + if (is_lobby_constructed()) {} l_dialog->exec(); delete l_dialog; diff --git a/src/aoapplication.h b/src/aoapplication.h index 1ff059b..c8c2444 100644 --- a/src/aoapplication.h +++ b/src/aoapplication.h @@ -61,18 +61,17 @@ public: ~AOApplication(); NetworkManager *net_manager; - Lobby *w_lobby; - Courtroom *w_courtroom; + Lobby *w_lobby = nullptr; + Courtroom *w_courtroom = nullptr; AttorneyOnline::Discord *discord; QFont default_font; - bool lobby_constructed = false; - bool courtroom_constructed = false; - + bool is_lobby_constructed(); void construct_lobby(); void destruct_lobby(); + bool is_courtroom_constructed(); void construct_courtroom(); void destruct_courtroom(); diff --git a/src/aoblipplayer.cpp b/src/aoblipplayer.cpp index cf877fd..3a13d78 100644 --- a/src/aoblipplayer.cpp +++ b/src/aoblipplayer.cpp @@ -1,64 +1,54 @@ #include "aoblipplayer.h" -AOBlipPlayer::AOBlipPlayer(AOApplication *p_ao_app) - : ao_app(p_ao_app) +AOBlipPlayer::AOBlipPlayer(AOApplication *ao_app) + : ao_app(ao_app) {} -void AOBlipPlayer::set_blips(QString p_sfx) +void AOBlipPlayer::setVolume(int value) { - QString f_path = ao_app->get_sfx_suffix(ao_app->get_sounds_path(p_sfx)); + m_volume = value; + updateInternalVolume(); +} - for (int n_stream = 0; n_stream < 5; ++n_stream) +void AOBlipPlayer::setMuted(bool enabled) +{ + m_muted = enabled; + updateInternalVolume(); +} + +void AOBlipPlayer::setBlip(QString blip) +{ + QString path = ao_app->get_sfx_suffix(ao_app->get_sounds_path(blip)); + for (int i = 0; i < STREAM_COUNT; ++i) { - BASS_StreamFree(m_stream_list[n_stream]); + BASS_StreamFree(m_stream[i]); - if (f_path.endsWith(".opus")) + if (path.endsWith(".opus")) { - m_stream_list[n_stream] = BASS_OPUS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); + m_stream[i] = BASS_OPUS_StreamCreateFile(FALSE, path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); } else { - m_stream_list[n_stream] = BASS_StreamCreateFile(FALSE, f_path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); + m_stream[i] = BASS_StreamCreateFile(FALSE, path.utf16(), 0, 0, BASS_UNICODE | BASS_ASYNCFILE); } } - set_volume_internal(m_volume); + updateInternalVolume(); } -void AOBlipPlayer::blip_tick() +void AOBlipPlayer::playBlip() { - int f_cycle = m_cycle++; + HSTREAM stream = m_stream[m_cycle]; + BASS_ChannelSetDevice(stream, BASS_GetDevice()); + BASS_ChannelPlay(stream, false); + m_cycle = ++m_cycle % STREAM_COUNT; +} - if (m_cycle == 5) +void AOBlipPlayer::updateInternalVolume() +{ + float volume = m_muted ? 0.0f : (m_volume * 0.01); + for (int i = 0; i < STREAM_COUNT; ++i) { - m_cycle = 0; - } - - HSTREAM f_stream = m_stream_list[f_cycle]; - - BASS_ChannelSetDevice(f_stream, BASS_GetDevice()); - BASS_ChannelPlay(f_stream, false); -} - -void AOBlipPlayer::set_muted(bool toggle) -{ - m_muted = toggle; - set_volume_internal(m_volume); -} - -void AOBlipPlayer::set_volume(int p_value) -{ - m_volume = static_cast(p_value) / 100; - set_volume_internal(m_volume); -} - -void AOBlipPlayer::set_volume_internal(qreal p_value) -{ - // If muted, volume will always be 0 - float volume = static_cast(p_value) * !m_muted; - - for (int n_stream = 0; n_stream < 5; ++n_stream) - { - BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); + BASS_ChannelSetAttribute(m_stream[i], BASS_ATTRIB_VOL, volume); } } diff --git a/src/aoblipplayer.h b/src/aoblipplayer.h index bc878b8..c33e08b 100644 --- a/src/aoblipplayer.h +++ b/src/aoblipplayer.h @@ -13,19 +13,24 @@ class AOBlipPlayer { public: - AOBlipPlayer(AOApplication *p_ao_app); + static constexpr int STREAM_COUNT = 5; - void set_blips(QString p_sfx); - void blip_tick(); - void set_volume(int p_volume); - void set_muted(bool toggle); + AOBlipPlayer(AOApplication *ao_app); + + void setVolume(int value); + void setMuted(bool enabled); + + void setBlip(QString blip); + + void playBlip(); private: AOApplication *ao_app; - qreal m_volume = 0.0; - int m_cycle = 0; - bool m_muted = false; - HSTREAM m_stream_list[5]; - void set_volume_internal(qreal p_volume); + int m_volume = 0; + bool m_muted = false; + HSTREAM m_stream[STREAM_COUNT]{}; + int m_cycle = 0; + + void updateInternalVolume(); }; diff --git a/src/aoemotepreview.cpp b/src/aoemotepreview.cpp index 8df35dd..e427cb8 100644 --- a/src/aoemotepreview.cpp +++ b/src/aoemotepreview.cpp @@ -1,44 +1,45 @@ #include "aoemotepreview.h" -AOEmotePreview::AOEmotePreview(AOApplication *p_ao_app, QWidget *parent) +AOEmotePreview::AOEmotePreview(AOApplication *ao_app, QWidget *parent) : QWidget(parent) - , ao_app(p_ao_app) + , ao_app(ao_app) { + setWindowFlag(Qt::Tool); + setWindowFlag(Qt::WindowMinMaxButtonsHint, false); + ui_viewport = new QWidget(this); ui_vp_player_char = new CharLayer(ao_app, ui_viewport); ui_vp_player_char->setObjectName("ui_vp_player_char"); ui_vp_player_char->masked = false; ui_size_label = new QLabel(this); ui_size_label->setObjectName("ui_size_label"); - setWindowFlag(Qt::WindowMinMaxButtonsHint, false); - setWindowFlag(Qt::Tool); - this->resize(256, 192); } -void AOEmotePreview::set_widgets() +void AOEmotePreview::updateViewportGeometry() { - ui_viewport->resize(this->width(), this->height()); + ui_viewport->resize(size()); ui_vp_player_char->move_and_center(0, 0); ui_vp_player_char->combo_resize(ui_viewport->width(), ui_viewport->height()); - ui_size_label->setText(QString::number(this->width()) + "x" + QString::number(this->height())); + ui_size_label->setText(QString::number(width()) + "x" + QString::number(height())); } -void AOEmotePreview::play(QString emote, QString char_name, bool flipped, int self_offset, int self_offset_v) +void AOEmotePreview::display(QString character, QString emote, bool flipped, int xOffset, int yOffset) { + m_character = character; + m_emote = emote; ui_vp_player_char->stop(); ui_vp_player_char->set_flipped(flipped); - ui_vp_player_char->move_and_center(ui_viewport->width() * self_offset / 100, ui_viewport->height() * self_offset_v / 100); - ui_vp_player_char->load_image(emote, char_name, 0, false); + ui_vp_player_char->move_and_center(ui_viewport->width() * xOffset / 100, ui_viewport->height() * yOffset / 100); + ui_vp_player_char->load_image(emote, character, 0, false); ui_vp_player_char->set_play_once(false); - m_emote = emote; - m_char = char_name; - setWindowTitle(char_name + ": " + emote); + setWindowTitle(character + ": " + emote); } -void AOEmotePreview::resizeEvent(QResizeEvent *) +void AOEmotePreview::resizeEvent(QResizeEvent *event) { - set_widgets(); - ui_vp_player_char->load_image(m_emote, m_char, 0, false); + QWidget::resizeEvent(event); + updateViewportGeometry(); + ui_vp_player_char->load_image(m_emote, m_character, 0, false); } diff --git a/src/aoemotepreview.h b/src/aoemotepreview.h index ac86ff0..0cf88c9 100644 --- a/src/aoemotepreview.h +++ b/src/aoemotepreview.h @@ -8,19 +8,20 @@ class AOEmotePreview : public QWidget Q_OBJECT public: - AOEmotePreview(AOApplication *p_ao_app, QWidget *parent = nullptr); + AOEmotePreview(AOApplication *ao_app, QWidget *parent = nullptr); - void set_widgets(); - void play(QString emote, QString char_name, bool flipped = false, int self_offset = 0, int self_offset_v = 0); + void display(QString character, QString emote, bool flipped = false, int xOffset = 0, int yOffset = 0); + + void updateViewportGeometry(); protected: - void resizeEvent(QResizeEvent *); + void resizeEvent(QResizeEvent *event); private: AOApplication *ao_app; + QString m_character; QString m_emote; - QString m_char; QWidget *ui_viewport; BackgroundLayer *ui_vp_background; diff --git a/src/aoevidencedisplay.cpp b/src/aoevidencedisplay.cpp index 6a5cf95..489699e 100644 --- a/src/aoevidencedisplay.cpp +++ b/src/aoevidencedisplay.cpp @@ -24,7 +24,7 @@ void AOEvidenceDisplay::show_evidence(int p_index, QString p_evidence_image, boo m_last_evidence_index = p_index; - m_sfx_player->set_volume(p_volume); + m_sfx_player->setVolume(p_volume); QString gif_name; QString icon_identifier; @@ -56,7 +56,7 @@ void AOEvidenceDisplay::show_evidence(int p_index, QString p_evidence_image, boo m_evidence_movie->max_duration = 1000; m_evidence_movie->set_play_once(true); m_evidence_movie->load_image(gif_name, ""); - m_sfx_player->play(ao_app->get_court_sfx("evidence_present")); + m_sfx_player->findAndPlaySfx(ao_app->get_court_sfx("evidence_present")); } void AOEvidenceDisplay::reset() diff --git a/src/aomusicplayer.cpp b/src/aomusicplayer.cpp index b9e6ab9..4265a46 100644 --- a/src/aomusicplayer.cpp +++ b/src/aomusicplayer.cpp @@ -9,48 +9,52 @@ #include #include -AOMusicPlayer::AOMusicPlayer(AOApplication *p_ao_app) - : ao_app(p_ao_app) +AOMusicPlayer::AOMusicPlayer(AOApplication *ao_app) + : ao_app(ao_app) {} AOMusicPlayer::~AOMusicPlayer() { - for (int n_stream = 0; n_stream < CHANNEL_COUNT; ++n_stream) + for (int n_stream = 0; n_stream < STREAM_COUNT; ++n_stream) { BASS_ChannelStop(m_stream_list[n_stream]); } } -QString AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_flags) +QString AOMusicPlayer::playStream(QString song, int streamId, bool loopEnabled, int effectFlags) { - channel = channel % CHANNEL_COUNT; - if (channel < 0) // wtf? + if (!ensureValidStreamId(streamId)) { return "[ERROR] Invalid Channel"; } - unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE; - unsigned int streaming_flags = BASS_STREAM_AUTOFREE; - if (loop) + + quint32 flags = BASS_STREAM_AUTOFREE; + if (loopEnabled) { flags |= BASS_SAMPLE_LOOP; - streaming_flags |= BASS_SAMPLE_LOOP; } - QString f_path = p_song; + + QString f_path = song; DWORD newstream; if (f_path.startsWith("http")) { if (!Options::getInstance().streamingEnabled()) { - BASS_ChannelStop(m_stream_list[channel]); + BASS_ChannelStop(m_stream_list[streamId]); return QObject::tr("[MISSING] Streaming disabled."); } QUrl l_url = QUrl(f_path); - newstream = BASS_StreamCreateURL(l_url.toEncoded().toStdString().c_str(), 0, streaming_flags, nullptr, 0); + newstream = BASS_StreamCreateURL(l_url.toEncoded().toStdString().c_str(), 0, flags, nullptr, 0); } else { - f_path = ao_app->get_real_path(ao_app->get_music_path(p_song)); - if (f_path.endsWith(".mo3") || f_path.endsWith(".xm") || f_path.endsWith(".mod") || f_path.endsWith(".s3m") || f_path.endsWith(".it") || f_path.endsWith(".mtm") || f_path.endsWith(".umx")) + flags |= BASS_STREAM_PRESCAN | BASS_UNICODE | BASS_ASYNCFILE; + + f_path = ao_app->get_real_path(ao_app->get_music_path(song)); + + QString extension = f_path.split('.').last(); + static const QStringList VALID_EXTENSION_LIST{"mo3", "xm", "mod", "s3m", "it", "mtm", "umx"}; + if (VALID_EXTENSION_LIST.contains(extension, Qt::CaseInsensitive)) { newstream = BASS_MusicLoad(FALSE, f_path.utf16(), 0, 0, flags, 1); } @@ -60,18 +64,17 @@ QString AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_f } } - int error_code = BASS_ErrorGetCode(); - + int error = BASS_ErrorGetCode(); if (Options::getInstance().audioOutputDevice() != "default") { - BASS_ChannelSetDevice(m_stream_list[channel], BASS_GetDevice()); + BASS_ChannelSetDevice(m_stream_list[streamId], BASS_GetDevice()); } - QString d_path = f_path + ".txt"; + m_loop_start[streamId] = 0; + m_loop_end[streamId] = 0; - m_loop_start[channel] = 0; - m_loop_end[channel] = 0; - if (loop && file_exists(d_path)) // Contains loop/etc. information file + QString d_path = f_path + ".txt"; + if (loopEnabled && file_exists(d_path)) // Contains loop/etc. information file { QStringList lines = ao_app->read_file(d_path).split("\n"); bool seconds_mode = false; @@ -90,6 +93,7 @@ QString AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_f seconds_mode = true; // Use new epic behavior continue; } + continue; } @@ -114,25 +118,25 @@ QString AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_f } if (arg == "loop_start") { - m_loop_start[channel] = bytes; + m_loop_start[streamId] = bytes; } else if (arg == "loop_length") { - m_loop_end[channel] = m_loop_start[channel] + bytes; + m_loop_end[streamId] = m_loop_start[streamId] + bytes; } else if (arg == "loop_end") { - m_loop_end[channel] = bytes; + m_loop_end[streamId] = bytes; } } - qDebug() << "Found data file for song" << p_song << "length" << BASS_ChannelGetLength(newstream, BASS_POS_BYTE) << "loop start" << m_loop_start[channel] << "loop end" << m_loop_end[channel]; + qDebug() << "Found data file for song" << song << "length" << BASS_ChannelGetLength(newstream, BASS_POS_BYTE) << "loop start" << m_loop_start[streamId] << "loop end" << m_loop_end[streamId]; } - if (BASS_ChannelIsActive(m_stream_list[channel]) == BASS_ACTIVE_PLAYING) + if (BASS_ChannelIsActive(m_stream_list[streamId]) == BASS_ACTIVE_PLAYING) { - DWORD oldstream = m_stream_list[channel]; + DWORD oldstream = m_stream_list[streamId]; - if (effect_flags & SYNC_POS) + if (effectFlags & SYNC_POS) { BASS_ChannelLock(oldstream, true); // Sync it with the new sample @@ -140,7 +144,7 @@ QString AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_f BASS_ChannelLock(oldstream, false); } - if ((effect_flags & FADE_OUT) && m_volume[channel] > 0) + if ((effectFlags & FADE_OUT) && m_volume[streamId] > 0) { // Fade out the other sample and stop it (due to -1) BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL | BASS_SLIDE_LOG, -1, 4000); @@ -152,47 +156,47 @@ QString AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_f } else { - BASS_ChannelStop(m_stream_list[channel]); + BASS_ChannelStop(m_stream_list[streamId]); } - m_stream_list[channel] = newstream; + m_stream_list[streamId] = newstream; BASS_ChannelPlay(newstream, false); - if (effect_flags & FADE_IN) + if (effectFlags & FADE_IN) { // Fade in our sample BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0); - BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast(m_volume[channel] / 100.0f), 1000); + BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast(m_volume[streamId] / 100.0f), 1000); } else { - this->set_volume(m_volume[channel], channel); + this->setStreamVolume(m_volume[streamId], streamId); } BASS_ChannelSetSync(newstream, BASS_SYNC_DEV_FAIL, 0, ao_app->BASSreset, 0); - this->set_looping(loop, channel); // Have to do this here due to any - // crossfading-related changes, etc. + this->setStreamLooping(loopEnabled, streamId); // Have to do this here due to any + // crossfading-related changes, etc. - bool is_stop = (p_song == "~stop.mp3"); - QString p_song_clear = QUrl(p_song).fileName(); + bool is_stop = (song == "~stop.mp3"); + QString p_song_clear = QUrl(song).fileName(); p_song_clear = p_song_clear.left(p_song_clear.lastIndexOf('.')); - if (is_stop && channel == 0) + if (is_stop && streamId == 0) { // don't send text on channels besides 0 return QObject::tr("None"); } - if (error_code == BASS_ERROR_HANDLE) + if (error == BASS_ERROR_HANDLE) { // Cheap hack to see if file missing return QObject::tr("[MISSING] %1").arg(p_song_clear); } - if (p_song.startsWith("http") && channel == 0) + if (song.startsWith("http") && streamId == 0) { return QObject::tr("[STREAM] %1").arg(p_song_clear); } - if (channel == 0) + if (streamId == 0) { return p_song_clear; } @@ -200,36 +204,37 @@ QString AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_f return ""; } -void AOMusicPlayer::stop(int channel) +void AOMusicPlayer::setMuted(bool enabled) { - BASS_ChannelStop(m_stream_list[channel]); -} - -void AOMusicPlayer::set_muted(bool toggle) -{ - m_muted = toggle; + m_muted = enabled; // Update all volume based on the mute setting - for (int n_stream = 0; n_stream < CHANNEL_COUNT; ++n_stream) + for (int n_stream = 0; n_stream < STREAM_COUNT; ++n_stream) { - set_volume(m_volume[n_stream], n_stream); + setStreamVolume(m_volume[n_stream], n_stream); } } -void AOMusicPlayer::set_volume(int p_value, int channel) +void AOMusicPlayer::setStreamVolume(int value, int streamId) { - m_volume[channel] = p_value; - // If muted, volume will always be 0 - float volume = (m_volume[channel] / 100.0f) * !m_muted; - if (channel < 0) + if (!ensureValidStreamId(streamId)) { - for (int n_stream = 0; n_stream < CHANNEL_COUNT; ++n_stream) + qWarning().noquote() << QObject::tr("Invalid stream ID '%2'").arg(streamId); + return; + } + + m_volume[streamId] = value; + // If muted, volume will always be 0 + float volume = (m_volume[streamId] / 100.0f) * !m_muted; + if (streamId < 0) + { + for (int n_stream = 0; n_stream < STREAM_COUNT; ++n_stream) { BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); } } else { - BASS_ChannelSetAttribute(m_stream_list[channel], BASS_ATTRIB_VOL, volume); + BASS_ChannelSetAttribute(m_stream_list[streamId], BASS_ATTRIB_VOL, volume); } } @@ -243,37 +248,48 @@ void CALLBACK loopProc(HSYNC handle, DWORD channel, DWORD data, void *user) BASS_ChannelLock(channel, false); } -void AOMusicPlayer::set_looping(bool loop_song, int channel) +void AOMusicPlayer::setStreamLooping(bool enabled, int streamId) { - if (!loop_song) + if (!ensureValidStreamId(streamId)) { - if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) - { - BASS_ChannelFlags(m_stream_list[channel], 0, - BASS_SAMPLE_LOOP); // remove the LOOP flag - } - BASS_ChannelRemoveSync(m_stream_list[channel], m_loop_sync[channel]); - m_loop_sync[channel] = 0; + qWarning().noquote() << QObject::tr("Invalid stream ID '%2'").arg(streamId); return; } - BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, - BASS_SAMPLE_LOOP); // set the LOOP flag - if (m_loop_sync[channel] != 0) + if (!enabled) { - BASS_ChannelRemoveSync(m_stream_list[channel], - m_loop_sync[channel]); // remove the sync - m_loop_sync[channel] = 0; + if (BASS_ChannelFlags(m_stream_list[streamId], 0, 0) & BASS_SAMPLE_LOOP) + { + BASS_ChannelFlags(m_stream_list[streamId], 0, + BASS_SAMPLE_LOOP); // remove the LOOP flag + } + BASS_ChannelRemoveSync(m_stream_list[streamId], m_loop_sync[streamId]); + m_loop_sync[streamId] = 0; + return; } - if (m_loop_start[channel] < m_loop_end[channel]) + BASS_ChannelFlags(m_stream_list[streamId], BASS_SAMPLE_LOOP, + BASS_SAMPLE_LOOP); // set the LOOP flag + if (m_loop_sync[streamId] != 0) + { + BASS_ChannelRemoveSync(m_stream_list[streamId], + m_loop_sync[streamId]); // remove the sync + m_loop_sync[streamId] = 0; + } + + if (m_loop_start[streamId] < m_loop_end[streamId]) { // Loop when the endpoint is reached. - m_loop_sync[channel] = BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_POS | BASS_SYNC_MIXTIME, m_loop_end[channel], loopProc, &m_loop_start[channel]); + m_loop_sync[streamId] = BASS_ChannelSetSync(m_stream_list[streamId], BASS_SYNC_POS | BASS_SYNC_MIXTIME, m_loop_end[streamId], loopProc, &m_loop_start[streamId]); } else { // Loop when the end of the file is reached. - m_loop_sync[channel] = BASS_ChannelSetSync(m_stream_list[channel], BASS_SYNC_END | BASS_SYNC_MIXTIME, 0, loopProc, &m_loop_start[channel]); + m_loop_sync[streamId] = BASS_ChannelSetSync(m_stream_list[streamId], BASS_SYNC_END | BASS_SYNC_MIXTIME, 0, loopProc, &m_loop_start[streamId]); } } + +bool AOMusicPlayer::ensureValidStreamId(int streamId) +{ + return (streamId >= 0 && streamId < STREAM_COUNT); +} diff --git a/src/aomusicplayer.h b/src/aomusicplayer.h index 248a45e..707d64a 100644 --- a/src/aomusicplayer.h +++ b/src/aomusicplayer.h @@ -7,38 +7,32 @@ class AOMusicPlayer { public: - // Channel 0 = music - // Channel 1 = ambience - static constexpr int CHANNEL_COUNT = 2; + // 0 = music + // 1 = ambience + static constexpr int STREAM_COUNT = 2; - AOMusicPlayer(AOApplication *p_ao_app); + explicit AOMusicPlayer(AOApplication *ao_app); virtual ~AOMusicPlayer(); - void set_volume(int p_value, int channel = -1); - void set_looping(bool loop_song, int channel = 0); - void set_muted(bool toggle); + void setMuted(bool enabled); - QFutureWatcher music_watcher; + QString playStream(QString song, int streamId, bool loopEnabled, int effectFlags); -public Q_SLOTS: - QString play(QString p_song, int channel = 0, bool loop = false, int effect_flags = 0); - void stop(int channel = 0); + void setStreamVolume(int value, int streamId); + void setStreamLooping(bool enabled, int streamId); + + QFutureWatcher m_watcher; private: AOApplication *ao_app; bool m_muted = false; - int m_volume[CHANNEL_COUNT] = {0, 0}; - HSTREAM m_stream_list[CHANNEL_COUNT]; - HSYNC m_loop_sync[CHANNEL_COUNT]; - /** - * @brief The starting sample of the AB-Loop. - */ - unsigned int m_loop_start[CHANNEL_COUNT] = {0, 0}; + int m_volume[STREAM_COUNT]{}; + HSTREAM m_stream_list[STREAM_COUNT]{}; + HSYNC m_loop_sync[STREAM_COUNT]{}; + quint32 m_loop_start[STREAM_COUNT]{}; + quint32 m_loop_end[STREAM_COUNT]{}; - /** - * @brief The end sample of the AB-Loop. - */ - unsigned int m_loop_end[CHANNEL_COUNT] = {0, 0}; + bool ensureValidStreamId(int streamId); }; diff --git a/src/aopacket.cpp b/src/aopacket.cpp index 705bc6a..cb924cb 100644 --- a/src/aopacket.cpp +++ b/src/aopacket.cpp @@ -10,6 +10,9 @@ QString AOPacket::decode(QString data) return data.replace("", "#").replace("", "%").replace("", "$").replace("", "&"); } +AOPacket::AOPacket() +{} + AOPacket::AOPacket(QString header) : m_header(header) {} diff --git a/src/aopacket.h b/src/aopacket.h index 11b1dfd..91fb1f7 100644 --- a/src/aopacket.h +++ b/src/aopacket.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -9,6 +10,7 @@ public: static QString encode(QString data); static QString decode(QString data); + AOPacket(); AOPacket(QString header); AOPacket(QString header, QStringList content); @@ -21,3 +23,4 @@ private: QString m_header; QStringList m_content; }; +Q_DECLARE_METATYPE(AOPacket) diff --git a/src/aosfxplayer.cpp b/src/aosfxplayer.cpp index 1b9be00..96b5d45 100644 --- a/src/aosfxplayer.cpp +++ b/src/aosfxplayer.cpp @@ -2,111 +2,135 @@ #include "file_functions.h" -AOSfxPlayer::AOSfxPlayer(AOApplication *p_ao_app) - : ao_app(p_ao_app) +AOSfxPlayer::AOSfxPlayer(AOApplication *ao_app) + : ao_app(ao_app) {} -void AOSfxPlayer::clear() -{ - for (int n_stream = 0; n_stream < CHANNEL_COUNT; ++n_stream) - { - BASS_ChannelStop(m_stream_list[n_stream]); - } - set_volume_internal(m_volume); -} - -void AOSfxPlayer::loop_clear() -{ - for (int n_stream = 0; n_stream < CHANNEL_COUNT; ++n_stream) - { - if ((BASS_ChannelFlags(m_stream_list[n_stream], 0, 0) & BASS_SAMPLE_LOOP)) - { - BASS_ChannelStop(m_stream_list[n_stream]); - } - } - set_volume_internal(m_volume); -} - -void AOSfxPlayer::play(QString p_sfx, QString p_character, QString p_misc) -{ - for (int i = 0; i < CHANNEL_COUNT; ++i) - { - if (BASS_ChannelIsActive(m_stream_list[i]) == BASS_ACTIVE_PLAYING) - { - m_channel = (i + 1) % CHANNEL_COUNT; - } - else - { - m_channel = i; - break; - } - } - QString path = ao_app->get_sfx(p_sfx, p_misc, p_character); - if (path.endsWith(".opus")) - { - m_stream_list[m_channel] = BASS_OPUS_StreamCreateFile(FALSE, path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); - } - else - { - m_stream_list[m_channel] = BASS_StreamCreateFile(FALSE, path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); - } - - set_volume_internal(m_volume); - - BASS_ChannelSetDevice(m_stream_list[m_channel], BASS_GetDevice()); - BASS_ChannelPlay(m_stream_list[m_channel], false); - BASS_ChannelSetSync(m_stream_list[m_channel], BASS_SYNC_DEV_FAIL, 0, ao_app->BASSreset, 0); -} - -void AOSfxPlayer::stop(int channel) -{ - if (channel == -1) - { - channel = m_channel; - } - BASS_ChannelStop(m_stream_list[channel]); -} - -void AOSfxPlayer::set_muted(bool toggle) -{ - m_muted = toggle; - // Update the audio volume - set_volume_internal(m_volume); -} - -int AOSfxPlayer::get_volume() +int AOSfxPlayer::volume() { return m_volume * 100; } -void AOSfxPlayer::set_volume(qreal p_value) +void AOSfxPlayer::setVolume(int value) { - m_volume = p_value * 0.01; - set_volume_internal(m_volume); + m_volume = value; + updateInternalVolume(); } -void AOSfxPlayer::set_volume_internal(qreal p_value) +void AOSfxPlayer::play(QString path) { - // If muted, volume will always be 0 - float volume = static_cast(p_value) * !m_muted; - for (int n_stream = 0; n_stream < CHANNEL_COUNT; ++n_stream) + for (int i = 0; i < STREAM_COUNT; ++i) { - BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume); + if (BASS_ChannelIsActive(m_stream[i]) == BASS_ACTIVE_PLAYING) + { + m_current_stream_id = (i + 1) % STREAM_COUNT; + } + else + { + m_current_stream_id = i; + break; + } + } + + if (path.endsWith(".opus")) + { + m_stream[m_current_stream_id] = BASS_OPUS_StreamCreateFile(FALSE, path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + } + else + { + m_stream[m_current_stream_id] = BASS_StreamCreateFile(FALSE, path.utf16(), 0, 0, BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE); + } + + updateInternalVolume(); + + BASS_ChannelSetDevice(m_stream[m_current_stream_id], BASS_GetDevice()); + BASS_ChannelPlay(m_stream[m_current_stream_id], false); + BASS_ChannelSetSync(m_stream[m_current_stream_id], BASS_SYNC_DEV_FAIL, 0, ao_app->BASSreset, 0); +} + +void AOSfxPlayer::findAndPlaySfx(QString sfx) +{ + // TODO replace this with proper pathing tools + findAndPlayCharacterShout(sfx, QString(), QString()); +} + +void AOSfxPlayer::findAndPlayCharacterSfx(QString sfx, QString character) +{ + // TODO replace this with proper pathing tools + findAndPlayCharacterShout(sfx, character, QString()); +} + +void AOSfxPlayer::findAndPlayCharacterShout(QString shout, QString character, QString group) +{ + QString file_path = ao_app->get_sfx(shout, group, character); + if (file_exists(file_path)) + { + play(file_path); } } -void AOSfxPlayer::set_looping(bool toggle, int channel) +void AOSfxPlayer::stopAll() { - if (channel == -1) + for (int i = 0; i < STREAM_COUNT; ++i) { - channel = m_channel; + stop(i); } +} + +void AOSfxPlayer::stopAllLoopingStream() +{ + for (int i = 0; i < STREAM_COUNT; ++i) + { + if (BASS_ChannelFlags(m_stream[i], 0, 0) & BASS_SAMPLE_LOOP) + { + stop(i); + } + } +} + +void AOSfxPlayer::stop(int streamId) +{ + streamId = maybeFetchCurrentStreamId(streamId); + if (!ensureValidStreamId(streamId)) + { + qWarning().noquote() << QObject::tr("Failed to stop stream; invalid stream ID '%1'").arg(streamId); + return; + } + + BASS_ChannelStop(m_stream[streamId]); +} + +void AOSfxPlayer::setMuted(bool toggle) +{ + m_muted = toggle; + // Update the audio volume + updateInternalVolume(); +} + +void AOSfxPlayer::updateInternalVolume() +{ + float volume = m_muted ? 0.0f : m_volume; + for (int i = 0; i < STREAM_COUNT; ++i) + { + BASS_ChannelSetAttribute(m_stream[i], BASS_ATTRIB_VOL, volume); + } +} + +void AOSfxPlayer::setLooping(bool toggle, int streamId) +{ + streamId = maybeFetchCurrentStreamId(streamId); + if (!ensureValidStreamId(streamId)) + { + qWarning().noquote() << QObject::tr("Failed to setup stream loop; invalid stream ID '%1'").arg(streamId); + return; + } + m_looping = toggle; - if (BASS_ChannelFlags(m_stream_list[channel], 0, 0) & BASS_SAMPLE_LOOP) + if (BASS_ChannelFlags(m_stream[streamId], 0, 0) & BASS_SAMPLE_LOOP) { if (m_looping == false) { - BASS_ChannelFlags(m_stream_list[channel], 0, + BASS_ChannelFlags(m_stream[streamId], 0, BASS_SAMPLE_LOOP); // remove the LOOP flag } } @@ -114,8 +138,18 @@ void AOSfxPlayer::set_looping(bool toggle, int channel) { if (m_looping == true) { - BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP, + BASS_ChannelFlags(m_stream[streamId], BASS_SAMPLE_LOOP, BASS_SAMPLE_LOOP); // set the LOOP flag } } } + +int AOSfxPlayer::maybeFetchCurrentStreamId(int streamId) +{ + return streamId == -1 ? m_current_stream_id : streamId; +} + +bool AOSfxPlayer::ensureValidStreamId(int streamId) +{ + return streamId >= 0 && streamId < STREAM_COUNT; +} diff --git a/src/aosfxplayer.h b/src/aosfxplayer.h index 6a71a71..5996956 100644 --- a/src/aosfxplayer.h +++ b/src/aosfxplayer.h @@ -11,28 +11,35 @@ class AOSfxPlayer { public: - static constexpr int CHANNEL_COUNT = 5; + static constexpr int STREAM_COUNT = 5; - AOSfxPlayer(AOApplication *p_ao_app); + AOSfxPlayer(AOApplication *ao_app); - int get_volume(); + int volume(); + void setVolume(int value); - void clear(); - void loop_clear(); - void play(QString p_sfx, QString p_char = QString(), QString shout = QString()); - void stop(int channel = -1); - void set_volume(qreal p_volume); - void set_looping(bool toggle, int channel = -1); - void set_muted(bool toggle); + void play(QString path); + void stop(int streamId = -1); + void stopAll(); + void stopAllLoopingStream(); + + void findAndPlaySfx(QString sfx); + void findAndPlayCharacterSfx(QString sfx, QString character); + void findAndPlayCharacterShout(QString shout, QString character, QString group); + + void setMuted(bool toggle); + void setLooping(bool toggle, int streamId = -1); private: AOApplication *ao_app; - qreal m_volume = 0.0; - bool m_looping = true; + int m_volume = 0; bool m_muted = false; - int m_channel = 0; - HSTREAM m_stream_list[CHANNEL_COUNT]{}; + bool m_looping = true; + HSTREAM m_stream[STREAM_COUNT]{}; + int m_current_stream_id = 0; - void set_volume_internal(qreal p_volume); + int maybeFetchCurrentStreamId(int streamId); + bool ensureValidStreamId(int streamId); + void updateInternalVolume(); }; diff --git a/src/aotextarea.cpp b/src/aotextarea.cpp index cf65124..08885da 100644 --- a/src/aotextarea.cpp +++ b/src/aotextarea.cpp @@ -1,16 +1,16 @@ #include "aotextarea.h" -AOTextArea::AOTextArea(QWidget *p_parent) - : AOTextArea(5000, p_parent) +AOTextArea::AOTextArea(QWidget *parent) + : AOTextArea(5000, parent) {} -AOTextArea::AOTextArea(int p_log_length, QWidget *p_parent) - : QTextBrowser(p_parent) +AOTextArea::AOTextArea(int maximumLogLenth, QWidget *parent) + : QTextBrowser(parent) { - this->document()->setMaximumBlockCount(p_log_length); + document()->setMaximumBlockCount(maximumLogLenth); } -void AOTextArea::append_chatmessage(QString p_name, QString p_message, QString p_name_colour, QString p_color) +void AOTextArea::addMessage(QString name, QString message, QString nameColor, QString messageColor) { const QTextCursor old_cursor = this->textCursor(); const int old_scrollbar_value = this->verticalScrollBar()->value(); @@ -19,19 +19,19 @@ void AOTextArea::append_chatmessage(QString p_name, QString p_message, QString p this->moveCursor(QTextCursor::End); this->append(""); - if (!p_name.isEmpty()) + if (!name.isEmpty()) { - this->insertHtml("" + p_name.toHtmlEscaped() + ": "); + this->insertHtml("" + name.toHtmlEscaped() + ": "); // cheap workarounds ahoy - p_message += " "; + message += " "; } - QString result = p_message.toHtmlEscaped().replace("\n", "
").replace(url_parser_regex, "\\1"); + QString result = message.toHtmlEscaped().replace("\n", "
").replace(url_parser_regex, "\\1"); - if (!p_color.isEmpty()) + if (!messageColor.isEmpty()) { - result = "" + result + ""; + result = "" + result + ""; } this->insertHtml(result); diff --git a/src/aotextarea.h b/src/aotextarea.h index b6f6ec6..b24ab2d 100644 --- a/src/aotextarea.h +++ b/src/aotextarea.h @@ -11,10 +11,10 @@ class AOTextArea : public QTextBrowser Q_OBJECT public: - AOTextArea(QWidget *p_parent = nullptr); - AOTextArea(int p_log_length, QWidget *p_parent = nullptr); + AOTextArea(QWidget *parent = nullptr); + AOTextArea(int maximumLogLenth, QWidget *parent = nullptr); - void append_chatmessage(QString p_name, QString p_message, QString p_name_colour, QString p_color = QString()); + void addMessage(QString name, QString message, QString nameColor, QString messageColor = QString()); private: const QRegularExpression url_parser_regex = QRegularExpression("\\b(https?://\\S+\\.\\S+)\\b"); diff --git a/src/charselect.cpp b/src/charselect.cpp index 4b62cb1..bc4032f 100644 --- a/src/charselect.cpp +++ b/src/charselect.cpp @@ -338,7 +338,7 @@ void Courtroom::character_loading_finished() // This part here serves as a way of showing to the player that the game is // still running, it is just loading the pictures of the characters. - if (ao_app->lobby_constructed) + if (ao_app->is_lobby_constructed()) { ao_app->generated_chars++; } diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 215bbb8..1f1c3cd 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -28,20 +28,20 @@ Courtroom::Courtroom(AOApplication *p_ao_app) sfx_delay_timer->setSingleShot(true); music_player = new AOMusicPlayer(ao_app); - music_player->set_muted(true); - connect(&music_player->music_watcher, &QFutureWatcher::finished, this, &Courtroom::update_ui_music_name, Qt::QueuedConnection); + music_player->setMuted(true); + connect(&music_player->m_watcher, &QFutureWatcher::finished, this, &Courtroom::update_ui_music_name, Qt::QueuedConnection); sfx_player = new AOSfxPlayer(ao_app); - sfx_player->set_muted(true); + sfx_player->setMuted(true); objection_player = new AOSfxPlayer(ao_app); - objection_player->set_muted(true); + objection_player->setMuted(true); blip_player = new AOBlipPlayer(ao_app); - blip_player->set_muted(true); + blip_player->setMuted(true); modcall_player = new AOSfxPlayer(ao_app); - modcall_player->set_volume(50); + modcall_player->setVolume(50); ui_background = new AOImage(ao_app, this); ui_background->setObjectName("ui_background"); @@ -552,15 +552,15 @@ void Courtroom::update_audio_volume() remaining_percent = 0; } - music_player->set_volume(ui_music_slider->value() * remaining_percent, 0); // set music + music_player->setStreamVolume(ui_music_slider->value() * remaining_percent, 0); // set music // Set the ambience and other misc. music layers - for (int i = 1; i < music_player->CHANNEL_COUNT; ++i) + for (int i = 1; i < music_player->STREAM_COUNT; ++i) { - music_player->set_volume(ui_sfx_slider->value() * remaining_percent, i); + music_player->setStreamVolume(ui_sfx_slider->value() * remaining_percent, i); } - sfx_player->set_volume(ui_sfx_slider->value() * remaining_percent); - objection_player->set_volume(ui_sfx_slider->value() * remaining_percent); - blip_player->set_volume(ui_blip_slider->value() * remaining_percent); + sfx_player->setVolume(ui_sfx_slider->value() * remaining_percent); + objection_player->setVolume(ui_sfx_slider->value() * remaining_percent); + blip_player->setVolume(ui_blip_slider->value() * remaining_percent); } void Courtroom::append_char(CharacterSlot p_char) @@ -1688,10 +1688,10 @@ void Courtroom::enter_courtroom() } // Unmute everything - music_player->set_muted(false); - objection_player->set_muted(false); - sfx_player->set_muted(false); - blip_player->set_muted(false); + music_player->setMuted(false); + objection_player->setMuted(false); + sfx_player->setMuted(false); + blip_player->setMuted(false); // Update the audio sliders update_audio_volume(); @@ -1866,7 +1866,7 @@ void Courtroom::debug_message_handler(QtMsgType type, const QMessageLogContext & Q_UNUSED(context); const QMap colors = {{QtDebugMsg, "debug"}, {QtInfoMsg, "info"}, {QtWarningMsg, "warn"}, {QtCriticalMsg, "critical"}, {QtFatalMsg, "fatal"}}; const QString color_id = QString("debug_log_%1_color").arg(colors.value(type, "info")); - ui_debug_log->append_chatmessage(colors.value(type, "info"), msg, QString(), ao_app->get_color(color_id, "courtroom_fonts.ini").name()); + ui_debug_log->addMessage(colors.value(type, "info"), msg, QString(), ao_app->get_color(color_id, "courtroom_fonts.ini").name()); } void Courtroom::append_server_chatmessage(QString p_name, QString p_message, QString p_color) @@ -1887,7 +1887,7 @@ void Courtroom::append_server_chatmessage(QString p_name, QString p_message, QSt on_authentication_state_received(1); } - ui_server_chatlog->append_chatmessage(p_name, p_message, color); + ui_server_chatlog->addMessage(p_name, p_message, color); if (Options::getInstance().logToTextFileEnabled() && !ao_app->log_filename.isEmpty()) { @@ -2666,33 +2666,33 @@ bool Courtroom::handle_objection() { case 1: filename = "holdit_bubble"; - objection_player->play("holdit", m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); + objection_player->findAndPlayCharacterShout("holdit", m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); break; case 2: filename = "objection_bubble"; - objection_player->play("objection", m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); + objection_player->findAndPlayCharacterShout("objection", m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); break; case 3: filename = "takethat_bubble"; - objection_player->play("takethat", m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); + objection_player->findAndPlayCharacterShout("takethat", m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); break; // case 4 is AO2 only case 4: if (custom_objection != "") { filename = "custom_objections/" + custom_objection.left(custom_objection.lastIndexOf(".")); - objection_player->play(filename, m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); + objection_player->findAndPlayCharacterShout(filename, m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); } else { filename = "custom"; - objection_player->play("custom", m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); + objection_player->findAndPlayCharacterShout("custom", m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); } break; m_chatmessage[EMOTE_MOD] = QChar(PREANIM); } ui_vp_objection->load_image(filename, m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME])); - sfx_player->clear(); // Objection played! Cut all sfx. + sfx_player->stopAll(); // Objection played! Cut all sfx. ui_vp_player_char->set_play_once(true); return true; } @@ -2710,7 +2710,7 @@ void Courtroom::display_character() ui_vp_player_char->stop(); ui_vp_effect->stop(); // Clear all looping sfx to prevent obnoxiousness - sfx_player->loop_clear(); + sfx_player->stopAllLoopingStream(); // Hide the message and chatbox and handle the emotes ui_vp_message->hide(); ui_vp_chatbox->setVisible(chatbox_always_show); @@ -2991,7 +2991,7 @@ void Courtroom::do_effect(QString fx_path, QString fx_sound, QString p_char, QSt if (fx_sound != "") { - sfx_player->play(fx_sound); + sfx_player->findAndPlaySfx(fx_sound); } // Only check if effects are disabled after playing the sound if it exists @@ -3073,7 +3073,7 @@ void Courtroom::do_effect(QString fx_path, QString fx_sound, QString p_char, QSt void Courtroom::play_char_sfx(QString sfx_name) { - sfx_player->play(sfx_name); + sfx_player->findAndPlaySfx(sfx_name); } void Courtroom::initialize_chatbox() @@ -3216,7 +3216,7 @@ void Courtroom::handle_callwords() if (f_message.contains(word, Qt::CaseInsensitive)) { // Play the call word sfx on the modcall_player sound container - modcall_player->play(ao_app->get_court_sfx("word_call")); + modcall_player->findAndPlaySfx(ao_app->get_court_sfx("word_call")); // Make the window flash ao_app->alert(this); // Break the loop so we don't spam sound effects @@ -3236,7 +3236,7 @@ void Courtroom::display_evidence_image() // QString f_evi_name = local_evidence_list.at(f_evi_id - 1).name; // def jud and hlp should display the evidence icon on the RIGHT side bool is_left_side = !(side == "def" || side == "hlp" || side == "jud" || side == "jur"); - ui_vp_evidence_display->show_evidence(f_evi_id, f_image, is_left_side, sfx_player->get_volume()); + ui_vp_evidence_display->show_evidence(f_evi_id, f_image, is_left_side, sfx_player->volume()); } } @@ -3930,7 +3930,7 @@ void Courtroom::start_chat_ticking() else if (m_chatmessage[REALIZATION] == "1") { this->do_flash(); - sfx_player->play(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); + sfx_player->findAndPlaySfx(ao_app->get_custom_realization(m_chatmessage[CHAR_NAME])); } int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); // text meme bonanza if ((emote_mod == IDLE || emote_mod == ZOOM) && m_chatmessage[SCREENSHAKE] == "1") @@ -4009,7 +4009,7 @@ void Courtroom::start_chat_ticking() { f_blips = ao_app->get_blips(m_chatmessage[BLIPNAME]); } - blip_player->set_blips(f_blips); + blip_player->setBlip(f_blips); // means text is currently ticking text_state = 1; @@ -4276,7 +4276,7 @@ void Courtroom::chat_tick() // ignoring white space unless blank_blip is enabled. if (!formatting_char && (f_character != ' ' || blank_blip)) { - blip_player->blip_tick(); + blip_player->playBlip(); ++blip_ticker; } } @@ -4335,10 +4335,10 @@ void Courtroom::play_sfx() return; } - sfx_player->play(sfx_name); + sfx_player->findAndPlaySfx(sfx_name); if (Options::getInstance().loopingSfx()) { - sfx_player->set_looping(ao_app->get_sfx_looping(current_char, current_emote) == "1"); + sfx_player->setLooping(ao_app->get_sfx_looping(current_char, current_emote) == "1"); } } @@ -4500,22 +4500,19 @@ void Courtroom::handle_song(QStringList *p_contents) { // Current song UI only displays the song playing, not other channels. // Any other music playing is irrelevant. - if (music_player->music_watcher.isRunning()) + if (music_player->m_watcher.isRunning()) { - music_player->music_watcher.cancel(); + music_player->m_watcher.cancel(); } ui_music_name->setText(tr("[LOADING] %1").arg(f_song_clear)); } -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - music_player->music_watcher.setFuture(QtConcurrent::run(music_player, &AOMusicPlayer::play, f_song, channel, looping, effect_flags)); -#else - music_player->music_watcher.setFuture(QtConcurrent::run(&AOMusicPlayer::play, music_player, f_song, channel, looping, effect_flags)); -#endif + + music_player->m_watcher.setFuture(QtConcurrent::run([=, this]() -> QString { return music_player->playStream(f_song, channel, looping, effect_flags); })); } void Courtroom::update_ui_music_name() { - QString result = music_player->music_watcher.result(); + QString result = music_player->m_watcher.result(); if (result.isEmpty()) { return; @@ -4590,7 +4587,7 @@ void Courtroom::handle_wtce(QString p_wtce, int variant) filename = p_wtce; } } - sfx_player->play(sfx_name); + sfx_player->findAndPlaySfx(sfx_name); ui_vp_wtce->load_image(filename, "", bg_misc); ui_vp_wtce->set_play_once(true); } @@ -4648,7 +4645,7 @@ void Courtroom::set_hp_bar(int p_bar, int p_state) if (!sfx_name.isEmpty()) { - sfx_player->play(sfx_name); + sfx_player->findAndPlaySfx(sfx_name); } } @@ -4678,7 +4675,7 @@ void Courtroom::mod_called(QString p_ip) ui_server_chatlog->append(p_ip); if (!ui_guard->isChecked()) { - modcall_player->play(ao_app->get_court_sfx("mod_call")); + modcall_player->findAndPlaySfx(ao_app->get_court_sfx("mod_call")); ao_app->alert(this); } } @@ -4703,11 +4700,7 @@ void Courtroom::on_ooc_return_pressed() if (ooc_message.startsWith("/load_case")) { -#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) - QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); -#else - QStringList command = ooc_message.split(" ", Qt::SkipEmptyParts); -#endif + QStringList command = ooc_message.split(" ", AOSplitBehaviorFlags::SkipEmptyParts); QDir casefolder(get_base_path() + "/cases"); if (!casefolder.exists()) { @@ -4803,11 +4796,7 @@ void Courtroom::on_ooc_return_pressed() } else if (ooc_message.startsWith("/save_case")) { -#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) - QStringList command = ooc_message.split(" ", QString::SkipEmptyParts); -#else - QStringList command = ooc_message.split(" ", Qt::SkipEmptyParts); -#endif + QStringList command = ooc_message.split(" ", AOSplitBehaviorFlags::SkipEmptyParts); QDir casefolder(get_base_path() + "cases"); if (!casefolder.exists()) { @@ -5265,7 +5254,7 @@ void Courtroom::on_sfx_context_menu_requested(const QPoint &pos) void Courtroom::on_sfx_play_clicked() { - sfx_player->play(get_char_sfx(), get_current_char()); + sfx_player->findAndPlayCharacterSfx(get_char_sfx(), get_current_char()); } void Courtroom::on_sfx_edit_requested() @@ -6063,25 +6052,25 @@ void Courtroom::on_text_color_changed(int p_color) void Courtroom::on_music_slider_moved(int p_value) { - music_player->set_volume(p_value, 0); // Set volume on music layer + music_player->setStreamVolume(p_value, 0); // Set volume on music layer ui_ic_chat_message->setFocus(); } void Courtroom::on_sfx_slider_moved(int p_value) { - sfx_player->set_volume(p_value); + sfx_player->setVolume(p_value); // Set the ambience and other misc. music layers - for (int i = 1; i < music_player->CHANNEL_COUNT; ++i) + for (int i = 1; i < music_player->STREAM_COUNT; ++i) { - music_player->set_volume(p_value, i); + music_player->setStreamVolume(p_value, i); } - objection_player->set_volume(p_value); + objection_player->setVolume(p_value); ui_ic_chat_message->setFocus(); } void Courtroom::on_blip_slider_moved(int p_value) { - blip_player->set_volume(p_value); + blip_player->setVolume(p_value); ui_ic_chat_message->setFocus(); } @@ -6150,8 +6139,8 @@ void Courtroom::on_guilty_clicked() void Courtroom::on_change_character_clicked() { - sfx_player->set_muted(true); - blip_player->set_muted(true); + sfx_player->setMuted(true); + blip_player->setMuted(true); set_char_select(); diff --git a/src/datatypes.h b/src/datatypes.h index 1258136..ab92c2e 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -3,6 +3,12 @@ #include #include +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) +using AOSplitBehaviorFlags = QString::SplitBehaviorFlags; +#else +using AOSplitBehaviorFlags = Qt::SplitBehaviorFlags; +#endif + enum ServerConnectionType { TcpServerConnection, @@ -18,6 +24,8 @@ struct ServerInfo QString ip; int port; ServerConnectionType socket_type; + + inline QString toString() { return QString("%1 (<%2>%3:%4)").arg(name, SERVER_CONNECTION_TYPE_STRING_MAP.key(socket_type), ip, QString::number(port)); } }; struct CharacterSlot diff --git a/src/demoserver.cpp b/src/demoserver.cpp index 0573b84..22f383a 100644 --- a/src/demoserver.cpp +++ b/src/demoserver.cpp @@ -1,5 +1,7 @@ #include "demoserver.h" +#include "datatypes.h" + DemoServer::DemoServer(QObject *parent) : QObject(parent) { @@ -93,12 +95,7 @@ void DemoServer::recv_data() { QString in_data = QString::fromUtf8(client_sock->readAll()); -#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) - const QStringList packet_list = in_data.split("%", QString::SkipEmptyParts); -#else - const QStringList packet_list = in_data.split("%", Qt::SkipEmptyParts); -#endif - + const QStringList packet_list = in_data.split("%", AOSplitBehaviorFlags::SkipEmptyParts); for (const QString &packet : packet_list) { QStringList f_contents; diff --git a/src/emotes.cpp b/src/emotes.cpp index c12ceb6..4023b52 100644 --- a/src/emotes.cpp +++ b/src/emotes.cpp @@ -22,6 +22,7 @@ void Courtroom::initialize_emotes() emote_preview = new AOEmotePreview(ao_app, this); emote_preview->setObjectName("ui_emote_preview"); + emote_preview->resize(256, 192); connect(ui_emote_left, &AOButton::clicked, this, &Courtroom::on_emote_left_clicked); connect(ui_emote_right, &AOButton::clicked, this, &Courtroom::on_emote_right_clicked); @@ -262,7 +263,7 @@ void Courtroom::show_emote_menu(const QPoint &pos) emote_menu->setDefaultAction(emote_menu->addAction("Preview Selected", this, [this] { emote_preview->show(); emote_preview->raise(); - emote_preview->set_widgets(); + emote_preview->updateViewportGeometry(); update_emote_preview(); })); QString prefix; @@ -291,8 +292,8 @@ void Courtroom::preview_emote(QString f_emote) { emote_preview->show(); emote_preview->raise(); - emote_preview->set_widgets(); - emote_preview->play(f_emote, current_char, ui_flip->isChecked(), ui_pair_offset_spinbox->value(), ui_pair_vert_offset_spinbox->value()); + emote_preview->updateViewportGeometry(); + emote_preview->display(current_char, f_emote, ui_flip->isChecked(), ui_pair_offset_spinbox->value(), ui_pair_vert_offset_spinbox->value()); } void Courtroom::on_emote_left_clicked() diff --git a/src/main.cpp b/src/main.cpp index d582eb7..955b1ff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,6 +17,8 @@ int main(int argc, char *argv[]) { qSetMessagePattern("%{type}: %{if-category}%{category}: %{endif}%{message}"); + qRegisterMetaType(); + AOApplication main_app(argc, argv); #ifdef ANDROID diff --git a/src/net/netconnection.cpp b/src/net/netconnection.cpp new file mode 100644 index 0000000..63ca706 --- /dev/null +++ b/src/net/netconnection.cpp @@ -0,0 +1,5 @@ +#include "netconnection.h" + +NetConnection::NetConnection(QObject *parent) + : QObject(parent) +{} diff --git a/src/net/netconnection.h b/src/net/netconnection.h new file mode 100644 index 0000000..0b5d6be --- /dev/null +++ b/src/net/netconnection.h @@ -0,0 +1,28 @@ +#pragma once + +#include "aopacket.h" +#include "datatypes.h" + +#include + +class NetConnection : public QObject +{ + Q_OBJECT + +public: + explicit NetConnection(QObject *parent = nullptr); + + virtual bool isConnected() = 0; + + virtual void connectToServer(ServerInfo &server) = 0; + virtual void disconnectFromServer() = 0; + + virtual void sendPacket(AOPacket packet) = 0; + +Q_SIGNALS: + void connectedToServer(); + void disconnectedFromServer(); + void errorOccurred(QString error); + + void receivedPacket(AOPacket packet); +}; diff --git a/src/net/nettcpconnection.cpp b/src/net/nettcpconnection.cpp new file mode 100644 index 0000000..744eed9 --- /dev/null +++ b/src/net/nettcpconnection.cpp @@ -0,0 +1,102 @@ +#include "nettcpconnection.h" + +NetTcpConnection::NetTcpConnection(QObject *parent) + : NetConnection(parent) + , m_socket(new QTcpSocket(this)) + , m_last_state(QAbstractSocket::UnconnectedState) +{ +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + connect(m_socket, QOverload::of(&QAbstractSocket::error), this, &NetTcpConnection::onErrorOccurred); +#else + connect(m_socket, &QTcpSocket::errorOccurred, this, &NetTcpConnection::onErrorOccurred); +#endif + connect(m_socket, &QTcpSocket::stateChanged, this, &NetTcpConnection::onStateChanged); + connect(m_socket, &QTcpSocket::readyRead, this, &NetTcpConnection::onReadyRead); +} + +NetTcpConnection::~NetTcpConnection() +{ + m_socket->disconnect(this); + disconnectFromServer(); +} + +bool NetTcpConnection::isConnected() +{ + return m_last_state == QAbstractSocket::ConnectedState; +} + +void NetTcpConnection::connectToServer(ServerInfo &server) +{ + disconnectedFromServer(); + m_socket->connectToHost(server.ip, server.port); +} + +void NetTcpConnection::disconnectFromServer() +{ + m_socket->abort(); +} + +void NetTcpConnection::sendPacket(AOPacket packet) +{ + if (!isConnected()) + { + qWarning().noquote() << QObject::tr("Cannot send packet, not connected to server"); + return; + } + m_socket->write(packet.toString(true).toUtf8()); +} + +void NetTcpConnection::onErrorOccurred() +{ + Q_EMIT errorOccurred(m_socket->errorString()); +} + +void NetTcpConnection::onStateChanged(QAbstractSocket::SocketState state) +{ + m_last_state = state; + switch (state) + { + default: + break; + + case QAbstractSocket::ConnectedState: + m_cached_data.clear(); + Q_EMIT connectedToServer(); + break; + + case QAbstractSocket::UnconnectedState: + Q_EMIT disconnectFromServer(); + break; + } +} + +void NetTcpConnection::onReadyRead() +{ + m_cached_data += QString::fromUtf8(m_socket->readAll()); + if (!m_cached_data.endsWith('%')) + { + return; + } + + QStringList raw_packet_list = m_cached_data.split('%', AOSplitBehaviorFlags::SkipEmptyParts); + m_cached_data.clear(); + for (QString raw_packet : raw_packet_list) + { + if (!raw_packet.endsWith('#')) + { + Q_EMIT errorOccurred(QObject::tr("Malformed packet received %1").arg(raw_packet)); + continue; + } + raw_packet.chop(1); + + QStringList raw_content = raw_packet.split('#'); + + const QString header = raw_content.takeFirst(); + for (QString &data : raw_content) + { + data = AOPacket::decode(data); + } + + Q_EMIT receivedPacket(AOPacket(header, raw_content)); + } +} diff --git a/src/net/nettcpconnection.h b/src/net/nettcpconnection.h new file mode 100644 index 0000000..40dae19 --- /dev/null +++ b/src/net/nettcpconnection.h @@ -0,0 +1,31 @@ +#pragma once + +#include "aopacket.h" +#include "datatypes.h" +#include "netconnection.h" + +#include + +class NetTcpConnection : public NetConnection +{ +public: + NetTcpConnection(QObject *parent = nullptr); + virtual ~NetTcpConnection(); + + bool isConnected() override; + + void connectToServer(ServerInfo &server) override; + void disconnectFromServer() override; + + void sendPacket(AOPacket packet) override; + +private: + QTcpSocket *m_socket; + QAbstractSocket::SocketState m_last_state; + QString m_cached_data; + +private Q_SLOTS: + void onErrorOccurred(); + void onStateChanged(QAbstractSocket::SocketState state); + void onReadyRead(); +}; diff --git a/src/net/netwebsocketconnection.cpp b/src/net/netwebsocketconnection.cpp new file mode 100644 index 0000000..a9d2e10 --- /dev/null +++ b/src/net/netwebsocketconnection.cpp @@ -0,0 +1,97 @@ +#include "netwebsocketconnection.h" + +#include "networkmanager.h" + +#include +#include + +NetWebSocketConnection::NetWebSocketConnection(NetworkManager *networkManager) + : NetConnection(networkManager) + , m_network_manager(networkManager) + , m_socket(new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this)) + , m_last_state(QAbstractSocket::UnconnectedState) +{ + connect(m_socket, QOverload::of(&QWebSocket::error), this, &NetWebSocketConnection::onError); + connect(m_socket, &QWebSocket::stateChanged, this, &NetWebSocketConnection::onStateChanged); + connect(m_socket, &QWebSocket::textMessageReceived, this, &NetWebSocketConnection::onTextMessageReceived); +} + +NetWebSocketConnection::~NetWebSocketConnection() +{ + m_socket->disconnect(this); + disconnectFromServer(); +} + +bool NetWebSocketConnection::isConnected() +{ + return m_last_state == QAbstractSocket::ConnectedState; +} + +void NetWebSocketConnection::connectToServer(ServerInfo &server) +{ + disconnectFromServer(); + + QUrl url; + url.setScheme("ws"); + url.setHost(server.ip); + url.setPort(server.port); + + QNetworkRequest req(url); + req.setHeader(QNetworkRequest::UserAgentHeader, m_network_manager->get_user_agent()); + + m_socket->open(req); +} + +void NetWebSocketConnection::disconnectFromServer() +{ + if (isConnected()) + { + m_socket->close(QWebSocketProtocol::CloseCodeGoingAway); + } +} + +void NetWebSocketConnection::sendPacket(AOPacket packet) +{ + m_socket->sendTextMessage(packet.toString(true)); +} + +void NetWebSocketConnection::onError() +{ + Q_EMIT errorOccurred(m_socket->errorString()); +} + +void NetWebSocketConnection::onStateChanged(QAbstractSocket::SocketState state) +{ + m_last_state = state; + switch (state) + { + default: + break; + + case QAbstractSocket::ConnectedState: + Q_EMIT connectedToServer(); + break; + + case QAbstractSocket::UnconnectedState: + Q_EMIT disconnectFromServer(); + break; + } +} + +void NetWebSocketConnection::onTextMessageReceived(QString message) +{ + if (!message.endsWith("#%")) + { + return; + } + message.chop(2); + + QStringList raw_content = message.split('#'); + const QString header = raw_content.takeFirst(); + for (QString &data : raw_content) + { + data = AOPacket::decode(data); + } + + Q_EMIT receivedPacket(AOPacket(header, raw_content)); +} diff --git a/src/net/netwebsocketconnection.h b/src/net/netwebsocketconnection.h new file mode 100644 index 0000000..26f41a6 --- /dev/null +++ b/src/net/netwebsocketconnection.h @@ -0,0 +1,32 @@ +#pragma once + +#include "netconnection.h" + +class NetworkManager; + +#include + +class NetWebSocketConnection : public NetConnection +{ +public: + NetWebSocketConnection(NetworkManager *networkManager); + virtual ~NetWebSocketConnection(); + + bool isConnected() override; + + void connectToServer(ServerInfo &server) override; + void disconnectFromServer() override; + + void sendPacket(AOPacket packet) override; + +private: + NetworkManager *m_network_manager; + + QWebSocket *m_socket; + QAbstractSocket::SocketState m_last_state; + +private Q_SLOTS: + void onError(); + void onStateChanged(QAbstractSocket::SocketState state); + void onTextMessageReceived(QString message); +}; diff --git a/src/networkmanager.cpp b/src/networkmanager.cpp index e53b291..69ff839 100644 --- a/src/networkmanager.cpp +++ b/src/networkmanager.cpp @@ -3,6 +3,8 @@ #include "datatypes.h" #include "debug_functions.h" #include "lobby.h" +#include "net/nettcpconnection.h" +#include "net/netwebsocketconnection.h" #include "options.h" #include @@ -77,13 +79,18 @@ void NetworkManager::ms_request_finished(QNetworkReply *reply) } ao_app->set_server_list(server_list); - if (ao_app->lobby_constructed) + if (ao_app->is_lobby_constructed()) { ao_app->w_lobby->list_servers(); } reply->deleteLater(); } +QString NetworkManager::get_user_agent() const +{ + return QStringLiteral("AttorneyOnline/%1 (Desktop)").arg(ao_app->get_version_string()); +} + void NetworkManager::send_heartbeat() { // Ping the server periodically to tell the MS that you've been playing @@ -137,57 +144,62 @@ void NetworkManager::request_document(MSDocumentType document_type, const std::f }); } -void NetworkManager::connect_to_server(ServerInfo p_server) +void NetworkManager::connect_to_server(ServerInfo server) { disconnect_from_server(); - qInfo().nospace().noquote() << "connecting to " << p_server.ip << ":" << p_server.port; - - switch (p_server.socket_type) + qInfo().noquote() << QObject::tr("Connecting to %1").arg(server.toString()); + switch (server.socket_type) { default: - p_server.socket_type = TcpServerConnection; + server.socket_type = TcpServerConnection; [[fallthrough]]; case TcpServerConnection: - qInfo() << "using TCP backend"; - server_socket.tcp = new QTcpSocket(this); - - connect(server_socket.tcp, &QAbstractSocket::connected, this, [] { qDebug() << "established connection to server"; }); - connect(server_socket.tcp, &QIODevice::readyRead, this, [this] { handle_server_packet(QString::fromUtf8(server_socket.tcp->readAll())); }); - connect(server_socket.tcp, &QAbstractSocket::disconnected, ao_app, &AOApplication::server_disconnected); -#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) - connect(server_socket.tcp, QOverload::of(&QAbstractSocket::error), this, [this] { -#else - connect(server_socket.tcp, &QAbstractSocket::errorOccurred, this, [this] { -#endif - qCritical() << "TCP socket error:" << server_socket.tcp->errorString(); - }); - - server_socket.tcp->connectToHost(p_server.ip, p_server.port); + qInfo() << "Using TCP backend."; + m_connection = new NetTcpConnection(this); break; case WebSocketServerConnection: - qInfo() << "using WebSockets backend"; - server_socket.ws = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this); - - connect(server_socket.ws, &QWebSocket::connected, this, [] { qDebug() << "established connection to server"; }); - connect(server_socket.ws, &QWebSocket::textMessageReceived, this, &NetworkManager::handle_server_packet); - connect(server_socket.ws, &QWebSocket::disconnected, ao_app, &AOApplication::server_disconnected); - connect(server_socket.ws, QOverload::of(&QWebSocket::error), this, [this] { qCritical() << "WebSockets error:" << server_socket.ws->errorString(); }); - - QUrl url; - url.setScheme("ws"); - url.setHost(p_server.ip); - url.setPort(p_server.port); - QNetworkRequest req(url); - req.setHeader(QNetworkRequest::UserAgentHeader, get_user_agent()); - server_socket.ws->open(req); + qInfo() << "Using WebSockets backend."; + m_connection = new NetWebSocketConnection(this); break; } - connected = true; - active_connection_type = p_server.socket_type; + connect(m_connection, &NetConnection::connectedToServer, this, [] { qInfo() << "Established connection to server."; }); + connect(m_connection, &NetConnection::disconnectedFromServer, ao_app, &AOApplication::server_disconnected); + connect(m_connection, &NetConnection::errorOccurred, this, [](QString error) { qCritical() << "Connection error:" << error; }); + connect(m_connection, &NetConnection::receivedPacket, this, &NetworkManager::handle_server_packet); + + m_connection->connectToServer(server); +} + +void NetworkManager::disconnect_from_server() +{ + if (m_connection) + { + m_connection->disconnectFromServer(); + m_connection->deleteLater(); + m_connection = nullptr; + } +} + +void NetworkManager::ship_server_packet(AOPacket packet) +{ + if (!m_connection) + { + qCritical() << "Failed to ship packet; no connection."; + return; + } + + if (!m_connection->isConnected()) + { + qCritical() << "Failed to ship packet; not connected."; + return; + } + + qInfo().noquote() << "Sending packet:" << packet.toString(); + m_connection->sendPacket(packet); } void NetworkManager::join_to_server() @@ -195,98 +207,8 @@ void NetworkManager::join_to_server() ship_server_packet(AOPacket("askchaa").toString()); } -void NetworkManager::disconnect_from_server() +void NetworkManager::handle_server_packet(AOPacket packet) { - if (!connected) - { - return; - } - - switch (active_connection_type) - { - case TcpServerConnection: - server_socket.tcp->close(); - server_socket.tcp->deleteLater(); - break; - case WebSocketServerConnection: - server_socket.ws->close(QWebSocketProtocol::CloseCodeGoingAway); - server_socket.ws->deleteLater(); - break; - } - - connected = false; -} - -void NetworkManager::ship_server_packet(AOPacket p_packet) -{ - QString message = p_packet.toString(true); - switch (active_connection_type) - { - case TcpServerConnection: - server_socket.tcp->write(message.toUtf8()); - break; - - case WebSocketServerConnection: - server_socket.ws->sendTextMessage(message); - break; - } -} - -void NetworkManager::handle_server_packet(const QString &p_data) -{ - QString in_data = p_data; - - if (!p_data.endsWith("%")) - { - partial_packet = true; - temp_packet += in_data; - return; - } - - else - { - if (partial_packet) - { - in_data = temp_packet + in_data; - temp_packet = ""; - partial_packet = false; - } - } -#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) - const QStringList packet_list = in_data.split("%", QString::SkipEmptyParts); -#else - const QStringList packet_list = in_data.split("%", Qt::SkipEmptyParts); -#endif - - for (const QString &packet : packet_list) - { - QStringList f_contents; - // Packet should *always* end with # - if (packet.endsWith("#")) - { - f_contents = packet.chopped(1).split("#"); - } - // But, if it somehow doesn't, we should still be able to handle it - else - { - f_contents = packet.split("#"); - } - // Empty packets are suspicious! - if (f_contents.isEmpty()) - { - qWarning() << "WARNING: Empty packet received from server, skipping..."; - continue; - } - // Take the first arg as the command - QString command = f_contents.takeFirst(); - for (QString &data : f_contents) - { - data = AOPacket::decode(data); - } - - // The rest is contents of the packet - AOPacket f_packet(command, f_contents); - // Ship it to the server! - ao_app->server_packet_received(f_packet); - } + qInfo().noquote() << "Received packet:" << packet.toString(); + ao_app->server_packet_received(packet); } diff --git a/src/networkmanager.h b/src/networkmanager.h index 5cd8761..4ec539f 100644 --- a/src/networkmanager.h +++ b/src/networkmanager.h @@ -2,6 +2,7 @@ #include "aoapplication.h" #include "aopacket.h" +#include "net/netconnection.h" #include #include @@ -28,11 +29,13 @@ public: void connect_to_server(ServerInfo p_server); void disconnect_from_server(); + QString get_user_agent() const; + public Q_SLOTS: void get_server_list(); - void ship_server_packet(AOPacket p_packet); + void ship_server_packet(AOPacket packet); void join_to_server(); - void handle_server_packet(const QString &p_data); + void handle_server_packet(AOPacket packet); void request_document(MSDocumentType document_type, const std::function &cb); void send_heartbeat(); @@ -47,13 +50,7 @@ private: AOApplication *ao_app; QNetworkAccessManager *http; - union - { - QWebSocket *ws; - QTcpSocket *tcp; - } server_socket; - ServerConnectionType active_connection_type; - bool connected = false; + NetConnection *m_connection = nullptr; QTimer *heartbeat_timer; @@ -62,10 +59,5 @@ private: const int heartbeat_interval = 60 * 5 * 1000; - bool partial_packet = false; - QString temp_packet; - unsigned int s_decryptor = 5; - - QString get_user_agent() const { return QStringLiteral("AttorneyOnline/%1 (Desktop)").arg(ao_app->get_version_string()); } }; diff --git a/src/packet_distribution.cpp b/src/packet_distribution.cpp index cdedd5a..a8dc773 100644 --- a/src/packet_distribution.cpp +++ b/src/packet_distribution.cpp @@ -24,14 +24,10 @@ void AOApplication::append_to_demofile(QString packet_string) } } -void AOApplication::server_packet_received(AOPacket p_packet) +void AOApplication::server_packet_received(AOPacket packet) { - QStringList f_contents_encoded = p_packet.content(); - QString f_packet_encoded = p_packet.toString(); - - QString header = p_packet.header(); - QStringList f_contents = p_packet.content(); - QString f_packet = p_packet.toString(); + QString header = packet.header(); + QStringList content = packet.content(); bool log_to_demo = true; @@ -44,7 +40,7 @@ void AOApplication::server_packet_received(AOPacket p_packet) if (header == "decryptor") { - if (f_contents.size() == 0) + if (content.size() == 0) { return; } @@ -76,13 +72,13 @@ void AOApplication::server_packet_received(AOPacket p_packet) } else if (header == "ID") { - if (f_contents.size() < 2) + if (content.size() < 2) { return; } - client_id = f_contents.at(0).toInt(); - server_software = f_contents.at(1); + client_id = content.at(0).toInt(); + server_software = content.at(1); net_manager->server_connected(true); @@ -91,18 +87,18 @@ void AOApplication::server_packet_received(AOPacket p_packet) } else if (header == "CT") { - if (!courtroom_constructed || f_contents.size() < 2) + if (!is_courtroom_constructed() || content.size() < 2) { return; } - if (f_contents.size() == 3) + if (content.size() == 3) { - w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), f_contents.at(2)); + w_courtroom->append_server_chatmessage(content.at(0), content.at(1), content.at(2)); } else { - w_courtroom->append_server_chatmessage(f_contents.at(0), f_contents.at(1), "0"); + w_courtroom->append_server_chatmessage(content.at(0), content.at(1), "0"); } } else if (header == "FL") @@ -125,104 +121,102 @@ void AOApplication::server_packet_received(AOPacket p_packet) custom_blips_supported = false; log_to_demo = false; - if (f_packet.contains("yellowtext", Qt::CaseInsensitive)) + if (content.contains("yellowtext", Qt::CaseInsensitive)) { yellow_text_supported = true; } - if (f_packet.contains("prezoom", Qt::CaseInsensitive)) + if (content.contains("prezoom", Qt::CaseInsensitive)) { prezoom_supported = true; } - if (f_packet.contains("flipping", Qt::CaseInsensitive)) + if (content.contains("flipping", Qt::CaseInsensitive)) { flipping_supported = true; } - if (f_packet.contains("customobjections", Qt::CaseInsensitive)) + if (content.contains("customobjections", Qt::CaseInsensitive)) { custom_objection_supported = true; } - if (f_packet.contains("deskmod", Qt::CaseInsensitive)) + if (content.contains("deskmod", Qt::CaseInsensitive)) { desk_mod_supported = true; } - if (f_packet.contains("evidence", Qt::CaseInsensitive)) + if (content.contains("evidence", Qt::CaseInsensitive)) { evidence_supported = true; } - if (f_packet.contains("cccc_ic_support", Qt::CaseInsensitive)) + if (content.contains("cccc_ic_support", Qt::CaseInsensitive)) { cccc_ic_supported = true; } - if (f_packet.contains("arup", Qt::CaseInsensitive)) + if (content.contains("arup", Qt::CaseInsensitive)) { arup_supported = true; } - if (f_packet.contains("casing_alerts", Qt::CaseInsensitive)) + if (content.contains("casing_alerts", Qt::CaseInsensitive)) { casing_alerts_supported = true; } - if (f_packet.contains("modcall_reason", Qt::CaseInsensitive)) + if (content.contains("modcall_reason", Qt::CaseInsensitive)) { modcall_reason_supported = true; } - if (f_packet.contains("looping_sfx", Qt::CaseInsensitive)) + if (content.contains("looping_sfx", Qt::CaseInsensitive)) { looping_sfx_supported = true; } - if (f_packet.contains("additive", Qt::CaseInsensitive)) + if (content.contains("additive", Qt::CaseInsensitive)) { additive_supported = true; } - if (f_packet.contains("effects", Qt::CaseInsensitive)) + if (content.contains("effects", Qt::CaseInsensitive)) { effects_supported = true; } - if (f_packet.contains("y_offset", Qt::CaseInsensitive)) + if (content.contains("y_offset", Qt::CaseInsensitive)) { y_offset_supported = true; } - if (f_packet.contains("expanded_desk_mods", Qt::CaseInsensitive)) + if (content.contains("expanded_desk_mods", Qt::CaseInsensitive)) { expanded_desk_mods_supported = true; } - if (f_packet.contains("auth_packet", Qt::CaseInsensitive)) + if (content.contains("auth_packet", Qt::CaseInsensitive)) { auth_packet_supported = true; } - if (f_packet.contains("custom_blips", Qt::CaseInsensitive)) + if (content.contains("custom_blips", Qt::CaseInsensitive)) { custom_blips_supported = true; } log_to_demo = false; - - } else if (header == "PN") { - if (!lobby_constructed || f_contents.size() < 2) + if (!is_lobby_constructed() || content.size() < 2) { return; } - w_lobby->set_player_count(f_contents.at(0).toInt(), f_contents.at(1).toInt()); + w_lobby->set_player_count(content.at(0).toInt(), content.at(1).toInt()); - if (f_contents.size() >= 3) + if (content.size() >= 3) { - w_lobby->set_server_description(f_contents.at(2)); + w_lobby->set_server_description(content.at(2)); } log_to_demo = false; } else if (header == "SI") { - if (!lobby_constructed || f_contents.size() != 3) + if (!is_lobby_constructed() || content.size() != 3) { return; } - char_list_size = f_contents.at(0).toInt(); - evidence_list_size = f_contents.at(1).toInt(); - music_list_size = f_contents.at(2).toInt(); + char_list_size = content.at(0).toInt(); + evidence_list_size = content.at(1).toInt(); + music_list_size = content.at(2).toInt(); if (char_list_size < 0 || evidence_list_size < 0 || music_list_size < 0) { @@ -272,7 +266,7 @@ void AOApplication::server_packet_received(AOPacket p_packet) break; } - if (courtroom_constructed) + if (is_courtroom_constructed()) { w_courtroom->set_window_title(window_title); } @@ -301,14 +295,14 @@ void AOApplication::server_packet_received(AOPacket p_packet) } else if (header == "CharsCheck") { - if (!courtroom_constructed) + if (!is_courtroom_constructed()) { return; } - for (int n_char = 0; n_char < f_contents.size(); ++n_char) + for (int n_char = 0; n_char < content.size(); ++n_char) { - if (f_contents.at(n_char) == "-1") + if (content.at(n_char) == "-1") { w_courtroom->set_taken(n_char, true); } @@ -322,14 +316,14 @@ void AOApplication::server_packet_received(AOPacket p_packet) else if (header == "SC") { - if (!courtroom_constructed) + if (!is_courtroom_constructed()) { return; } w_courtroom->clear_chars(); - for (int n_element = 0; n_element < f_contents.size(); ++n_element) + for (int n_element = 0; n_element < content.size(); ++n_element) { - QStringList sub_elements = f_contents.at(n_element).split("&"); + QStringList sub_elements = content.at(n_element).split("&"); for (QString &sub_element : sub_elements) { sub_element = AOPacket::decode(sub_element); @@ -359,7 +353,7 @@ void AOApplication::server_packet_received(AOPacket p_packet) } else if (header == "SM") { - if (!courtroom_constructed || courtroom_loaded) + if (!is_courtroom_constructed() || courtroom_loaded) { return; } @@ -367,25 +361,25 @@ void AOApplication::server_packet_received(AOPacket p_packet) bool musics_time = false; int areas = 0; - for (int n_element = 0; n_element < f_contents.size(); ++n_element) + for (int n_element = 0; n_element < content.size(); ++n_element) { ++loaded_music; if (musics_time) { - w_courtroom->append_music(f_contents.at(n_element)); + w_courtroom->append_music(content.at(n_element)); } else { - if (f_contents.at(n_element).endsWith(".wav") || f_contents.at(n_element).endsWith(".mp3") || f_contents.at(n_element).endsWith(".mp4") || f_contents.at(n_element).endsWith(".ogg") || f_contents.at(n_element).endsWith(".opus")) + if (content.at(n_element).endsWith(".wav") || content.at(n_element).endsWith(".mp3") || content.at(n_element).endsWith(".mp4") || content.at(n_element).endsWith(".ogg") || content.at(n_element).endsWith(".opus")) { musics_time = true; w_courtroom->fix_last_area(); - w_courtroom->append_music(f_contents.at(n_element)); + w_courtroom->append_music(content.at(n_element)); areas--; } else { - w_courtroom->append_area(f_contents.at(n_element)); + w_courtroom->append_area(content.at(n_element)); areas++; } } @@ -401,16 +395,16 @@ void AOApplication::server_packet_received(AOPacket p_packet) } else if (header == "FM") // Fetch music ONLY { - if (!courtroom_constructed) + if (!is_courtroom_constructed()) { return; } w_courtroom->clear_music(); - for (int n_element = 0; n_element < f_contents.size(); ++n_element) + for (int n_element = 0; n_element < content.size(); ++n_element) { - w_courtroom->append_music(f_contents.at(n_element)); + w_courtroom->append_music(content.at(n_element)); } w_courtroom->list_music(); @@ -418,7 +412,7 @@ void AOApplication::server_packet_received(AOPacket p_packet) } else if (header == "FA") // Fetch areas ONLY { - if (!courtroom_constructed) + if (!is_courtroom_constructed()) { return; } @@ -426,9 +420,9 @@ void AOApplication::server_packet_received(AOPacket p_packet) w_courtroom->clear_areas(); w_courtroom->arup_clear(); - for (int n_element = 0; n_element < f_contents.size(); ++n_element) + for (int n_element = 0; n_element < content.size(); ++n_element) { - w_courtroom->append_area(f_contents.at(n_element)); + w_courtroom->append_area(content.at(n_element)); w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown"); } @@ -437,7 +431,7 @@ void AOApplication::server_packet_received(AOPacket p_packet) } else if (header == "DONE") { - if (!courtroom_constructed) + if (!is_courtroom_constructed()) { return; } @@ -452,99 +446,99 @@ void AOApplication::server_packet_received(AOPacket p_packet) } else if (header == "BN") { - if (!courtroom_constructed || f_contents.isEmpty()) + if (!is_courtroom_constructed() || content.isEmpty()) { return; } - if (f_contents.size() >= 2) + if (content.size() >= 2) { // We have a pos included in the background packet! - if (!f_contents.at(1).isEmpty()) + if (!content.at(1).isEmpty()) { // Not touching it when its empty. - w_courtroom->set_side(f_contents.at(1)); + w_courtroom->set_side(content.at(1)); } } - w_courtroom->set_background(f_contents.at(0), f_contents.size() >= 2); + w_courtroom->set_background(content.at(0), content.size() >= 2); } else if (header == "SP") { - if (!courtroom_constructed || f_contents.isEmpty()) + if (!is_courtroom_constructed() || content.isEmpty()) { return; } // We were sent a "set position" packet - w_courtroom->set_side(f_contents.at(0)); + w_courtroom->set_side(content.at(0)); } else if (header == "SD") // Send pos dropdown { - if (!courtroom_constructed || f_contents.isEmpty()) + if (!is_courtroom_constructed() || content.isEmpty()) { return; } - w_courtroom->set_pos_dropdown(f_contents.at(0).split("*")); + w_courtroom->set_pos_dropdown(content.at(0).split("*")); } // server accepting char request(CC) packet else if (header == "PV") { - if (!courtroom_constructed || f_contents.size() < 3) + if (!is_courtroom_constructed() || content.size() < 3) { return; } // For some reason, args 0 and 1 are not used (from tsu3 they're client ID and a string "CID") w_courtroom->enter_courtroom(); w_courtroom->set_courtroom_size(); - w_courtroom->update_character(f_contents.at(2).toInt()); + w_courtroom->update_character(content.at(2).toInt()); } else if (header == "MS") { - if (courtroom_constructed && courtroom_loaded) + if (is_courtroom_constructed() && courtroom_loaded) { - w_courtroom->chatmessage_enqueue(p_packet.content()); + w_courtroom->chatmessage_enqueue(packet.content()); } } else if (header == "MC") { - if (courtroom_constructed && courtroom_loaded) + if (is_courtroom_constructed() && courtroom_loaded) { - w_courtroom->handle_song(&p_packet.content()); + w_courtroom->handle_song(&packet.content()); } } else if (header == "RT") { - if (f_contents.isEmpty()) + if (content.isEmpty()) { return; } - if (courtroom_constructed) + if (is_courtroom_constructed()) { - if (f_contents.size() == 1) + if (content.size() == 1) { - w_courtroom->handle_wtce(f_contents.at(0), 0); + w_courtroom->handle_wtce(content.at(0), 0); } - else if (f_contents.size() >= 2) + else if (content.size() >= 2) { - w_courtroom->handle_wtce(f_contents.at(0), f_contents.at(1).toInt()); + w_courtroom->handle_wtce(content.at(0), content.at(1).toInt()); } } } else if (header == "HP") { - if (courtroom_constructed && f_contents.size() >= 2) + if (is_courtroom_constructed() && content.size() >= 2) { - w_courtroom->set_hp_bar(f_contents.at(0).toInt(), f_contents.at(1).toInt()); + w_courtroom->set_hp_bar(content.at(0).toInt(), content.at(1).toInt()); } } else if (header == "LE") { - if (courtroom_constructed) + if (is_courtroom_constructed()) { QVector f_evi_list; - for (QString f_string : f_contents_encoded) + for (QString f_string : packet.content()) { QStringList sub_contents = f_string.split("&"); if (sub_contents.size() < 3) @@ -572,12 +566,12 @@ void AOApplication::server_packet_received(AOPacket p_packet) } else if (header == "ARUP") { - if (courtroom_constructed && !f_contents.isEmpty()) + if (is_courtroom_constructed() && !content.isEmpty()) { - int arup_type = f_contents.at(0).toInt(); - for (int n_element = 1; n_element < f_contents.size(); n_element++) + int arup_type = content.at(0).toInt(); + for (int n_element = 1; n_element < content.size(); n_element++) { - w_courtroom->arup_modify(arup_type, n_element - 1, f_contents.at(n_element)); + w_courtroom->arup_modify(arup_type, n_element - 1, content.at(n_element)); } w_courtroom->list_areas(); } @@ -585,41 +579,41 @@ void AOApplication::server_packet_received(AOPacket p_packet) } else if (header == "IL") { - if (courtroom_constructed && !f_contents.isEmpty()) + if (is_courtroom_constructed() && !content.isEmpty()) { - w_courtroom->set_ip_list(f_contents.at(0)); + w_courtroom->set_ip_list(content.at(0)); } log_to_demo = false; } else if (header == "MU") { - if (courtroom_constructed && !f_contents.isEmpty()) + if (is_courtroom_constructed() && !content.isEmpty()) { - w_courtroom->set_mute(true, f_contents.at(0).toInt()); + w_courtroom->set_mute(true, content.at(0).toInt()); } log_to_demo = false; } else if (header == "UM") { - if (courtroom_constructed && !f_contents.isEmpty()) + if (is_courtroom_constructed() && !content.isEmpty()) { - w_courtroom->set_mute(false, f_contents.at(0).toInt()); + w_courtroom->set_mute(false, content.at(0).toInt()); log_to_demo = false; } } else if (header == "BB") { - if (courtroom_constructed && !f_contents.isEmpty()) + if (is_courtroom_constructed() && !content.isEmpty()) { - call_notice(f_contents.at(0)); + call_notice(content.at(0)); } log_to_demo = false; } else if (header == "KK") { - if (courtroom_constructed && !f_contents.isEmpty()) + if (is_courtroom_constructed() && !content.isEmpty()) { - call_notice(tr("You have been kicked from the server.\nReason: %1").arg(f_contents.at(0))); + call_notice(tr("You have been kicked from the server.\nReason: %1").arg(content.at(0))); construct_lobby(); destruct_courtroom(); } @@ -627,9 +621,9 @@ void AOApplication::server_packet_received(AOPacket p_packet) } else if (header == "KB") { - if (courtroom_constructed && !f_contents.isEmpty()) + if (is_courtroom_constructed() && !content.isEmpty()) { - call_notice(tr("You have been banned from the server.\nReason: %1").arg(f_contents.at(0))); + call_notice(tr("You have been banned from the server.\nReason: %1").arg(content.at(0))); construct_lobby(); destruct_courtroom(); } @@ -637,46 +631,46 @@ void AOApplication::server_packet_received(AOPacket p_packet) } else if (header == "BD") { - if (f_contents.isEmpty()) + if (content.isEmpty()) { return; } - call_notice(tr("You are banned on this server.\nReason: %1").arg(f_contents.at(0))); + call_notice(tr("You are banned on this server.\nReason: %1").arg(content.at(0))); log_to_demo = false; } else if (header == "ZZ") { - if (courtroom_constructed && !f_contents.isEmpty()) + if (is_courtroom_constructed() && !content.isEmpty()) { - w_courtroom->mod_called(f_contents.at(0)); + w_courtroom->mod_called(content.at(0)); } } else if (header == "TI") { // Timer packet - if (!courtroom_constructed || f_contents.size() < 2) + if (!is_courtroom_constructed() || content.size() < 2) { return; } // Timer ID is reserved as argument 0 - int id = f_contents.at(0).toInt(); + int id = content.at(0).toInt(); // Type 0 = start/resume/sync timer at time // Type 1 = pause timer at time // Type 2 = show timer // Type 3 = hide timer - int type = f_contents.at(1).toInt(); + int type = content.at(1).toInt(); if (type == 0 || type == 1) { - if (f_contents.size() < 3) + if (content.size() < 3) { return; } // The time as displayed on the clock, in milliseconds. // If the number received is negative, stop the timer. - qint64 timer_value = f_contents.at(2).toLongLong(); + qint64 timer_value = content.at(2).toLongLong(); if (timer_value > 0) { if (type == 0) @@ -706,7 +700,7 @@ void AOApplication::server_packet_received(AOPacket p_packet) } else if (header == "CHECK") { - if (!courtroom_constructed) + if (!is_courtroom_constructed()) { return; } @@ -722,12 +716,12 @@ void AOApplication::server_packet_received(AOPacket p_packet) // Subtheme packet else if (header == "ST") { - if (!courtroom_constructed || f_contents.isEmpty()) + if (!is_courtroom_constructed() || content.isEmpty()) { return; } // Subtheme reserved as argument 0 - subtheme = f_contents.at(0); + subtheme = content.at(0); // Check if we have subthemes set to "server" if (Options::getInstance().settingsSubTheme().toLower() != "server") @@ -737,7 +731,7 @@ void AOApplication::server_packet_received(AOPacket p_packet) } // Reload theme request - if (f_contents.size() > 1 && f_contents.at(1) == "1") + if (content.size() > 1 && content.at(1) == "1") { Options::getInstance().setServerSubTheme(subtheme); w_courtroom->on_reload_theme_clicked(); @@ -746,15 +740,15 @@ void AOApplication::server_packet_received(AOPacket p_packet) // Auth packet else if (header == "AUTH") { - if (!courtroom_constructed || !auth_packet_supported || f_contents.isEmpty()) + if (!is_courtroom_constructed() || !auth_packet_supported || content.isEmpty()) { return; } bool ok; - int authenticated = f_contents.at(0).toInt(&ok); + int authenticated = content.at(0).toInt(&ok); if (!ok) { - qWarning() << "Malformed AUTH packet! Contents:" << f_contents.at(0); + qWarning() << "Malformed AUTH packet! Contents:" << content.at(0); } w_courtroom->on_authentication_state_received(authenticated); @@ -762,12 +756,12 @@ void AOApplication::server_packet_received(AOPacket p_packet) } else if (header == "JD") { - if (!courtroom_constructed || f_contents.isEmpty()) + if (!is_courtroom_constructed() || content.isEmpty()) { return; } bool ok; - Courtroom::JudgeState state = static_cast(f_contents.at(0).toInt(&ok)); + Courtroom::JudgeState state = static_cast(content.at(0).toInt(&ok)); if (!ok) { return; // ignore malformed packet @@ -786,11 +780,11 @@ void AOApplication::server_packet_received(AOPacket p_packet) // AssetURL Packet else if (header == "ASS") { - if (f_contents.size() > 1 || f_contents.isEmpty()) + if (content.size() > 1 || content.isEmpty()) { // This can never be more than one link. return; } - QUrl t_asset_url = QUrl::fromPercentEncoding(f_contents.at(0).toUtf8()); + QUrl t_asset_url = QUrl::fromPercentEncoding(content.at(0).toUtf8()); if (t_asset_url.isValid()) { asset_url = t_asset_url.toString(); @@ -799,7 +793,7 @@ void AOApplication::server_packet_received(AOPacket p_packet) if (log_to_demo) { - append_to_demofile(f_packet_encoded); + append_to_demofile(packet.toString(true)); } } diff --git a/src/path_functions.cpp b/src/path_functions.cpp index 7953d92..d68535c 100644 --- a/src/path_functions.cpp +++ b/src/path_functions.cpp @@ -66,7 +66,7 @@ VPath AOApplication::get_music_path(QString p_song) VPath AOApplication::get_background_path(QString p_file) { - if (courtroom_constructed) + if (is_courtroom_constructed()) { return VPath("background/" + w_courtroom->get_current_background() + "/" + p_file); } diff --git a/src/text_file_functions.cpp b/src/text_file_functions.cpp index 0390225..e7c4511 100644 --- a/src/text_file_functions.cpp +++ b/src/text_file_functions.cpp @@ -447,13 +447,15 @@ QString AOApplication::get_showname(QString p_char, int p_emote) QString f_result = read_char_ini(p_char, "showname", "Options"); QString f_needed = read_char_ini(p_char, "needs_showname", "Options"); - if (p_emote != -1) { - int override_idx = - read_char_ini(p_char, QString::number(p_emote + 1), "OptionsN").toInt(); - if (override_idx > 0) { + if (p_emote != -1) + { + int override_idx = read_char_ini(p_char, QString::number(p_emote + 1), "OptionsN").toInt(); + if (override_idx > 0) + { QString override_key = "Options" + QString::number(override_idx); QString temp_f_result = read_char_ini(p_char, "showname", override_key); - if (!temp_f_result.isEmpty()) { + if (!temp_f_result.isEmpty()) + { f_result = temp_f_result; } } @@ -485,30 +487,38 @@ QString AOApplication::get_blipname(QString p_char, int p_emote) { QString f_result = read_char_ini(p_char, "blips", "Options"); - if (p_emote != -1) { - int override_idx = - read_char_ini(p_char, QString::number(p_emote + 1), "OptionsN").toInt(); - if (override_idx > 0) { + if (p_emote != -1) + { + int override_idx = read_char_ini(p_char, QString::number(p_emote + 1), "OptionsN").toInt(); + if (override_idx > 0) + { QString override_key = "Options" + QString::number(override_idx); QString temp_f_result = read_char_ini(p_char, "blips", override_key); - if (!temp_f_result.isEmpty()) { + if (!temp_f_result.isEmpty()) + { f_result = temp_f_result; } } } - if (f_result == "") { - f_result = - read_char_ini(p_char, "gender", "Options"); // not very PC, FanatSors - if (f_result == "") f_result = "male"; + if (f_result == "") + { + f_result = read_char_ini(p_char, "gender", "Options"); // not very PC, FanatSors + if (f_result == "") + { + f_result = "male"; + } } return f_result; } QString AOApplication::get_blips(QString p_blipname) { - if (!file_exists(get_sfx_suffix(get_sounds_path(p_blipname)))) { + if (!file_exists(get_sfx_suffix(get_sounds_path(p_blipname)))) + { if (file_exists(get_sfx_suffix(get_sounds_path("../blips/" + p_blipname)))) + { return "../blips/" + p_blipname; // Return the cool kids variant + } return "sfx-blip" + p_blipname; // Return legacy variant } diff --git a/src/widgets/server_editor_dialog.cpp b/src/widgets/server_editor_dialog.cpp index 102e903..386950e 100644 --- a/src/widgets/server_editor_dialog.cpp +++ b/src/widgets/server_editor_dialog.cpp @@ -4,6 +4,7 @@ #include "gui_utils.h" #include "options.h" +#include #include #include #include