Lightly reworked NetworkManager
, ...
* Lightly reworked `NetworkManager` * Added new modules to handle various connection types. * TCP * WebSocket * Added general string splitter alias based on Qt version. * Replaced `lobby_constructed` and `courtroom_constructed` * Refactored and partially reimplemented the following classes: * `AOBlipPlayer` * `AOEmotePreview` * `AOMusicPlayer` * `AOSfxPlayer` * `AOTextArea`
This commit is contained in:
parent
39e4354b1d
commit
1ef96383c8
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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<qreal>(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<float>(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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -9,48 +9,52 @@
|
||||
#include <QFuture>
|
||||
#include <QWidget>
|
||||
|
||||
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<float>(m_volume[channel] / 100.0f), 1000);
|
||||
BASS_ChannelSlideAttribute(newstream, BASS_ATTRIB_VOL, static_cast<float>(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);
|
||||
}
|
||||
|
@ -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<QString> 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<QString> 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);
|
||||
};
|
||||
|
@ -10,6 +10,9 @@ QString AOPacket::decode(QString data)
|
||||
return data.replace("<num>", "#").replace("<percent>", "%").replace("<dollar>", "$").replace("<and>", "&");
|
||||
}
|
||||
|
||||
AOPacket::AOPacket()
|
||||
{}
|
||||
|
||||
AOPacket::AOPacket(QString header)
|
||||
: m_header(header)
|
||||
{}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
@ -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)
|
||||
|
@ -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<float>(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;
|
||||
}
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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("<b><font color=" + p_name_colour + ">" + p_name.toHtmlEscaped() + "</font></b>: ");
|
||||
this->insertHtml("<b><font color=" + nameColor + ">" + name.toHtmlEscaped() + "</font></b>: ");
|
||||
|
||||
// cheap workarounds ahoy
|
||||
p_message += " ";
|
||||
message += " ";
|
||||
}
|
||||
|
||||
QString result = p_message.toHtmlEscaped().replace("\n", "<br>").replace(url_parser_regex, "<a href='\\1'>\\1</a>");
|
||||
QString result = message.toHtmlEscaped().replace("\n", "<br>").replace(url_parser_regex, "<a href='\\1'>\\1</a>");
|
||||
|
||||
if (!p_color.isEmpty())
|
||||
if (!messageColor.isEmpty())
|
||||
{
|
||||
result = "<font color=" + p_color + ">" + result + "</font>";
|
||||
result = "<font color=" + messageColor + ">" + result + "</font>";
|
||||
}
|
||||
|
||||
this->insertHtml(result);
|
||||
|
@ -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");
|
||||
|
@ -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++;
|
||||
}
|
||||
|
@ -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<QString>::finished, this, &Courtroom::update_ui_music_name, Qt::QueuedConnection);
|
||||
music_player->setMuted(true);
|
||||
connect(&music_player->m_watcher, &QFutureWatcher<QString>::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<QtMsgType, QString> 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();
|
||||
|
||||
|
@ -3,6 +3,12 @@
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
|
||||
#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
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -17,6 +17,8 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
qSetMessagePattern("%{type}: %{if-category}%{category}: %{endif}%{message}");
|
||||
|
||||
qRegisterMetaType<AOPacket>();
|
||||
|
||||
AOApplication main_app(argc, argv);
|
||||
|
||||
#ifdef ANDROID
|
||||
|
5
src/net/netconnection.cpp
Normal file
5
src/net/netconnection.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "netconnection.h"
|
||||
|
||||
NetConnection::NetConnection(QObject *parent)
|
||||
: QObject(parent)
|
||||
{}
|
28
src/net/netconnection.h
Normal file
28
src/net/netconnection.h
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "aopacket.h"
|
||||
#include "datatypes.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
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);
|
||||
};
|
102
src/net/nettcpconnection.cpp
Normal file
102
src/net/nettcpconnection.cpp
Normal file
@ -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<QAbstractSocket::SocketError>::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));
|
||||
}
|
||||
}
|
31
src/net/nettcpconnection.h
Normal file
31
src/net/nettcpconnection.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "aopacket.h"
|
||||
#include "datatypes.h"
|
||||
#include "netconnection.h"
|
||||
|
||||
#include <QTcpSocket>
|
||||
|
||||
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();
|
||||
};
|
97
src/net/netwebsocketconnection.cpp
Normal file
97
src/net/netwebsocketconnection.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
#include "netwebsocketconnection.h"
|
||||
|
||||
#include "networkmanager.h"
|
||||
|
||||
#include <QNetworkRequest>
|
||||
#include <QUrl>
|
||||
|
||||
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<QAbstractSocket::SocketError>::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));
|
||||
}
|
32
src/net/netwebsocketconnection.h
Normal file
32
src/net/netwebsocketconnection.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "netconnection.h"
|
||||
|
||||
class NetworkManager;
|
||||
|
||||
#include <QWebSocket>
|
||||
|
||||
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);
|
||||
};
|
@ -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 <QAbstractSocket>
|
||||
@ -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<QAbstractSocket::SocketError>::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<QAbstractSocket::SocketError>::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);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "aoapplication.h"
|
||||
#include "aopacket.h"
|
||||
#include "net/netconnection.h"
|
||||
|
||||
#include <QDnsLookup>
|
||||
#include <QNetworkAccessManager>
|
||||
@ -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<void(QString)> &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()); }
|
||||
};
|
||||
|
@ -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<EvidenceItem> 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<Courtroom::JudgeState>(f_contents.at(0).toInt(&ok));
|
||||
Courtroom::JudgeState state = static_cast<Courtroom::JudgeState>(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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "gui_utils.h"
|
||||
#include "options.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QUiLoader>
|
||||
#include <QVBoxLayout>
|
||||
|
Loading…
Reference in New Issue
Block a user