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.cpp
|
||||||
src/lobby.h
|
src/lobby.h
|
||||||
src/main.cpp
|
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.cpp
|
||||||
src/networkmanager.h
|
src/networkmanager.h
|
||||||
src/options.cpp
|
src/options.cpp
|
||||||
|
@ -40,16 +40,20 @@ AOApplication::~AOApplication()
|
|||||||
qInstallMessageHandler(original_message_handler);
|
qInstallMessageHandler(original_message_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AOApplication::is_lobby_constructed()
|
||||||
|
{
|
||||||
|
return w_lobby;
|
||||||
|
}
|
||||||
|
|
||||||
void AOApplication::construct_lobby()
|
void AOApplication::construct_lobby()
|
||||||
{
|
{
|
||||||
if (lobby_constructed)
|
if (is_lobby_constructed())
|
||||||
{
|
{
|
||||||
qWarning() << "lobby was attempted constructed when it already exists";
|
qWarning() << "lobby was attempted constructed when it already exists";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
w_lobby = new Lobby(this, net_manager);
|
w_lobby = new Lobby(this, net_manager);
|
||||||
lobby_constructed = true;
|
|
||||||
|
|
||||||
QRect geometry = QGuiApplication::primaryScreen()->geometry();
|
QRect geometry = QGuiApplication::primaryScreen()->geometry();
|
||||||
int x = (geometry.width() - w_lobby->width()) / 2;
|
int x = (geometry.width() - w_lobby->width()) / 2;
|
||||||
@ -71,7 +75,7 @@ void AOApplication::construct_lobby()
|
|||||||
|
|
||||||
void AOApplication::destruct_lobby()
|
void AOApplication::destruct_lobby()
|
||||||
{
|
{
|
||||||
if (!lobby_constructed)
|
if (!is_lobby_constructed())
|
||||||
{
|
{
|
||||||
qWarning() << "lobby was attempted destructed when it did not exist";
|
qWarning() << "lobby was attempted destructed when it did not exist";
|
||||||
return;
|
return;
|
||||||
@ -79,19 +83,22 @@ void AOApplication::destruct_lobby()
|
|||||||
|
|
||||||
delete w_lobby;
|
delete w_lobby;
|
||||||
w_lobby = nullptr;
|
w_lobby = nullptr;
|
||||||
lobby_constructed = false;
|
}
|
||||||
|
|
||||||
|
bool AOApplication::is_courtroom_constructed()
|
||||||
|
{
|
||||||
|
return w_courtroom;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOApplication::construct_courtroom()
|
void AOApplication::construct_courtroom()
|
||||||
{
|
{
|
||||||
if (courtroom_constructed)
|
if (is_courtroom_constructed())
|
||||||
{
|
{
|
||||||
qWarning() << "courtroom was attempted constructed when it already exists";
|
qWarning() << "courtroom was attempted constructed when it already exists";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
w_courtroom = new Courtroom(this);
|
w_courtroom = new Courtroom(this);
|
||||||
courtroom_constructed = true;
|
|
||||||
|
|
||||||
QRect geometry = QGuiApplication::primaryScreen()->geometry();
|
QRect geometry = QGuiApplication::primaryScreen()->geometry();
|
||||||
int x = (geometry.width() - w_courtroom->width()) / 2;
|
int x = (geometry.width() - w_courtroom->width()) / 2;
|
||||||
@ -110,7 +117,7 @@ void AOApplication::construct_courtroom()
|
|||||||
|
|
||||||
void AOApplication::destruct_courtroom()
|
void AOApplication::destruct_courtroom()
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed)
|
if (!is_courtroom_constructed())
|
||||||
{
|
{
|
||||||
qWarning() << "courtroom was attempted destructed when it did not exist";
|
qWarning() << "courtroom was attempted destructed when it did not exist";
|
||||||
return;
|
return;
|
||||||
@ -118,7 +125,6 @@ void AOApplication::destruct_courtroom()
|
|||||||
|
|
||||||
delete w_courtroom;
|
delete w_courtroom;
|
||||||
w_courtroom = nullptr;
|
w_courtroom = nullptr;
|
||||||
courtroom_constructed = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString AOApplication::get_version_string()
|
QString AOApplication::get_version_string()
|
||||||
@ -128,9 +134,12 @@ QString AOApplication::get_version_string()
|
|||||||
|
|
||||||
void AOApplication::server_disconnected()
|
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();
|
construct_lobby();
|
||||||
destruct_courtroom();
|
destruct_courtroom();
|
||||||
}
|
}
|
||||||
@ -145,12 +154,12 @@ void AOApplication::loading_cancelled()
|
|||||||
void AOApplication::call_settings_menu()
|
void AOApplication::call_settings_menu()
|
||||||
{
|
{
|
||||||
AOOptionsDialog *l_dialog = new AOOptionsDialog(this);
|
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);
|
connect(l_dialog, &AOOptionsDialog::reloadThemeRequest, w_courtroom, &Courtroom::on_reload_theme_clicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lobby_constructed)
|
if (is_lobby_constructed())
|
||||||
{}
|
{}
|
||||||
l_dialog->exec();
|
l_dialog->exec();
|
||||||
delete l_dialog;
|
delete l_dialog;
|
||||||
|
@ -61,18 +61,17 @@ public:
|
|||||||
~AOApplication();
|
~AOApplication();
|
||||||
|
|
||||||
NetworkManager *net_manager;
|
NetworkManager *net_manager;
|
||||||
Lobby *w_lobby;
|
Lobby *w_lobby = nullptr;
|
||||||
Courtroom *w_courtroom;
|
Courtroom *w_courtroom = nullptr;
|
||||||
AttorneyOnline::Discord *discord;
|
AttorneyOnline::Discord *discord;
|
||||||
|
|
||||||
QFont default_font;
|
QFont default_font;
|
||||||
|
|
||||||
bool lobby_constructed = false;
|
bool is_lobby_constructed();
|
||||||
bool courtroom_constructed = false;
|
|
||||||
|
|
||||||
void construct_lobby();
|
void construct_lobby();
|
||||||
void destruct_lobby();
|
void destruct_lobby();
|
||||||
|
|
||||||
|
bool is_courtroom_constructed();
|
||||||
void construct_courtroom();
|
void construct_courtroom();
|
||||||
void destruct_courtroom();
|
void destruct_courtroom();
|
||||||
|
|
||||||
|
@ -1,64 +1,54 @@
|
|||||||
#include "aoblipplayer.h"
|
#include "aoblipplayer.h"
|
||||||
|
|
||||||
AOBlipPlayer::AOBlipPlayer(AOApplication *p_ao_app)
|
AOBlipPlayer::AOBlipPlayer(AOApplication *ao_app)
|
||||||
: ao_app(p_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
|
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;
|
BASS_ChannelSetAttribute(m_stream[i], BASS_ATTRIB_VOL, volume);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,19 +13,24 @@
|
|||||||
class AOBlipPlayer
|
class AOBlipPlayer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AOBlipPlayer(AOApplication *p_ao_app);
|
static constexpr int STREAM_COUNT = 5;
|
||||||
|
|
||||||
void set_blips(QString p_sfx);
|
AOBlipPlayer(AOApplication *ao_app);
|
||||||
void blip_tick();
|
|
||||||
void set_volume(int p_volume);
|
void setVolume(int value);
|
||||||
void set_muted(bool toggle);
|
void setMuted(bool enabled);
|
||||||
|
|
||||||
|
void setBlip(QString blip);
|
||||||
|
|
||||||
|
void playBlip();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AOApplication *ao_app;
|
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"
|
#include "aoemotepreview.h"
|
||||||
|
|
||||||
AOEmotePreview::AOEmotePreview(AOApplication *p_ao_app, QWidget *parent)
|
AOEmotePreview::AOEmotePreview(AOApplication *ao_app, QWidget *parent)
|
||||||
: 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_viewport = new QWidget(this);
|
||||||
ui_vp_player_char = new CharLayer(ao_app, ui_viewport);
|
ui_vp_player_char = new CharLayer(ao_app, ui_viewport);
|
||||||
ui_vp_player_char->setObjectName("ui_vp_player_char");
|
ui_vp_player_char->setObjectName("ui_vp_player_char");
|
||||||
ui_vp_player_char->masked = false;
|
ui_vp_player_char->masked = false;
|
||||||
ui_size_label = new QLabel(this);
|
ui_size_label = new QLabel(this);
|
||||||
ui_size_label->setObjectName("ui_size_label");
|
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->move_and_center(0, 0);
|
||||||
ui_vp_player_char->combo_resize(ui_viewport->width(), ui_viewport->height());
|
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->stop();
|
||||||
ui_vp_player_char->set_flipped(flipped);
|
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->move_and_center(ui_viewport->width() * xOffset / 100, ui_viewport->height() * yOffset / 100);
|
||||||
ui_vp_player_char->load_image(emote, char_name, 0, false);
|
ui_vp_player_char->load_image(emote, character, 0, false);
|
||||||
ui_vp_player_char->set_play_once(false);
|
ui_vp_player_char->set_play_once(false);
|
||||||
m_emote = emote;
|
setWindowTitle(character + ": " + emote);
|
||||||
m_char = char_name;
|
|
||||||
setWindowTitle(char_name + ": " + emote);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOEmotePreview::resizeEvent(QResizeEvent *)
|
void AOEmotePreview::resizeEvent(QResizeEvent *event)
|
||||||
{
|
{
|
||||||
set_widgets();
|
QWidget::resizeEvent(event);
|
||||||
ui_vp_player_char->load_image(m_emote, m_char, 0, false);
|
updateViewportGeometry();
|
||||||
|
ui_vp_player_char->load_image(m_emote, m_character, 0, false);
|
||||||
}
|
}
|
||||||
|
@ -8,19 +8,20 @@ class AOEmotePreview : public QWidget
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AOEmotePreview(AOApplication *p_ao_app, QWidget *parent = nullptr);
|
AOEmotePreview(AOApplication *ao_app, QWidget *parent = nullptr);
|
||||||
|
|
||||||
void set_widgets();
|
void display(QString character, QString emote, bool flipped = false, int xOffset = 0, int yOffset = 0);
|
||||||
void play(QString emote, QString char_name, bool flipped = false, int self_offset = 0, int self_offset_v = 0);
|
|
||||||
|
void updateViewportGeometry();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *);
|
void resizeEvent(QResizeEvent *event);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AOApplication *ao_app;
|
AOApplication *ao_app;
|
||||||
|
|
||||||
|
QString m_character;
|
||||||
QString m_emote;
|
QString m_emote;
|
||||||
QString m_char;
|
|
||||||
|
|
||||||
QWidget *ui_viewport;
|
QWidget *ui_viewport;
|
||||||
BackgroundLayer *ui_vp_background;
|
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_last_evidence_index = p_index;
|
||||||
|
|
||||||
m_sfx_player->set_volume(p_volume);
|
m_sfx_player->setVolume(p_volume);
|
||||||
|
|
||||||
QString gif_name;
|
QString gif_name;
|
||||||
QString icon_identifier;
|
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->max_duration = 1000;
|
||||||
m_evidence_movie->set_play_once(true);
|
m_evidence_movie->set_play_once(true);
|
||||||
m_evidence_movie->load_image(gif_name, "");
|
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()
|
void AOEvidenceDisplay::reset()
|
||||||
|
@ -9,48 +9,52 @@
|
|||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
AOMusicPlayer::AOMusicPlayer(AOApplication *p_ao_app)
|
AOMusicPlayer::AOMusicPlayer(AOApplication *ao_app)
|
||||||
: ao_app(p_ao_app)
|
: ao_app(ao_app)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
AOMusicPlayer::~AOMusicPlayer()
|
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]);
|
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 (!ensureValidStreamId(streamId))
|
||||||
if (channel < 0) // wtf?
|
|
||||||
{
|
{
|
||||||
return "[ERROR] Invalid Channel";
|
return "[ERROR] Invalid Channel";
|
||||||
}
|
}
|
||||||
unsigned int flags = BASS_STREAM_PRESCAN | BASS_STREAM_AUTOFREE | BASS_UNICODE | BASS_ASYNCFILE;
|
|
||||||
unsigned int streaming_flags = BASS_STREAM_AUTOFREE;
|
quint32 flags = BASS_STREAM_AUTOFREE;
|
||||||
if (loop)
|
if (loopEnabled)
|
||||||
{
|
{
|
||||||
flags |= BASS_SAMPLE_LOOP;
|
flags |= BASS_SAMPLE_LOOP;
|
||||||
streaming_flags |= BASS_SAMPLE_LOOP;
|
|
||||||
}
|
}
|
||||||
QString f_path = p_song;
|
|
||||||
|
QString f_path = song;
|
||||||
DWORD newstream;
|
DWORD newstream;
|
||||||
if (f_path.startsWith("http"))
|
if (f_path.startsWith("http"))
|
||||||
{
|
{
|
||||||
if (!Options::getInstance().streamingEnabled())
|
if (!Options::getInstance().streamingEnabled())
|
||||||
{
|
{
|
||||||
BASS_ChannelStop(m_stream_list[channel]);
|
BASS_ChannelStop(m_stream_list[streamId]);
|
||||||
return QObject::tr("[MISSING] Streaming disabled.");
|
return QObject::tr("[MISSING] Streaming disabled.");
|
||||||
}
|
}
|
||||||
QUrl l_url = QUrl(f_path);
|
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
|
else
|
||||||
{
|
{
|
||||||
f_path = ao_app->get_real_path(ao_app->get_music_path(p_song));
|
flags |= BASS_STREAM_PRESCAN | BASS_UNICODE | BASS_ASYNCFILE;
|
||||||
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"))
|
|
||||||
|
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);
|
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")
|
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;
|
QString d_path = f_path + ".txt";
|
||||||
m_loop_end[channel] = 0;
|
if (loopEnabled && file_exists(d_path)) // Contains loop/etc. information file
|
||||||
if (loop && file_exists(d_path)) // Contains loop/etc. information file
|
|
||||||
{
|
{
|
||||||
QStringList lines = ao_app->read_file(d_path).split("\n");
|
QStringList lines = ao_app->read_file(d_path).split("\n");
|
||||||
bool seconds_mode = false;
|
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
|
seconds_mode = true; // Use new epic behavior
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,25 +118,25 @@ QString AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_f
|
|||||||
}
|
}
|
||||||
if (arg == "loop_start")
|
if (arg == "loop_start")
|
||||||
{
|
{
|
||||||
m_loop_start[channel] = bytes;
|
m_loop_start[streamId] = bytes;
|
||||||
}
|
}
|
||||||
else if (arg == "loop_length")
|
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")
|
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);
|
BASS_ChannelLock(oldstream, true);
|
||||||
// Sync it with the new sample
|
// 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);
|
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)
|
// Fade out the other sample and stop it (due to -1)
|
||||||
BASS_ChannelSlideAttribute(oldstream, BASS_ATTRIB_VOL | BASS_SLIDE_LOG, -1, 4000);
|
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
|
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);
|
BASS_ChannelPlay(newstream, false);
|
||||||
if (effect_flags & FADE_IN)
|
if (effectFlags & FADE_IN)
|
||||||
{
|
{
|
||||||
// Fade in our sample
|
// Fade in our sample
|
||||||
BASS_ChannelSetAttribute(newstream, BASS_ATTRIB_VOL, 0);
|
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
|
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);
|
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
|
this->setStreamLooping(loopEnabled, streamId); // Have to do this here due to any
|
||||||
// crossfading-related changes, etc.
|
// crossfading-related changes, etc.
|
||||||
|
|
||||||
bool is_stop = (p_song == "~stop.mp3");
|
bool is_stop = (song == "~stop.mp3");
|
||||||
QString p_song_clear = QUrl(p_song).fileName();
|
QString p_song_clear = QUrl(song).fileName();
|
||||||
p_song_clear = p_song_clear.left(p_song_clear.lastIndexOf('.'));
|
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
|
{ // don't send text on channels besides 0
|
||||||
return QObject::tr("None");
|
return QObject::tr("None");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error_code == BASS_ERROR_HANDLE)
|
if (error == BASS_ERROR_HANDLE)
|
||||||
{ // Cheap hack to see if file missing
|
{ // Cheap hack to see if file missing
|
||||||
return QObject::tr("[MISSING] %1").arg(p_song_clear);
|
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);
|
return QObject::tr("[STREAM] %1").arg(p_song_clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel == 0)
|
if (streamId == 0)
|
||||||
{
|
{
|
||||||
return p_song_clear;
|
return p_song_clear;
|
||||||
}
|
}
|
||||||
@ -200,36 +204,37 @@ QString AOMusicPlayer::play(QString p_song, int channel, bool loop, int effect_f
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOMusicPlayer::stop(int channel)
|
void AOMusicPlayer::setMuted(bool enabled)
|
||||||
{
|
{
|
||||||
BASS_ChannelStop(m_stream_list[channel]);
|
m_muted = enabled;
|
||||||
}
|
|
||||||
|
|
||||||
void AOMusicPlayer::set_muted(bool toggle)
|
|
||||||
{
|
|
||||||
m_muted = toggle;
|
|
||||||
// Update all volume based on the mute setting
|
// 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 (!ensureValidStreamId(streamId))
|
||||||
// If muted, volume will always be 0
|
|
||||||
float volume = (m_volume[channel] / 100.0f) * !m_muted;
|
|
||||||
if (channel < 0)
|
|
||||||
{
|
{
|
||||||
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);
|
BASS_ChannelSetAttribute(m_stream_list[n_stream], BASS_ATTRIB_VOL, volume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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);
|
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)
|
qWarning().noquote() << QObject::tr("Invalid stream ID '%2'").arg(streamId);
|
||||||
{
|
|
||||||
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;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BASS_ChannelFlags(m_stream_list[channel], BASS_SAMPLE_LOOP,
|
if (!enabled)
|
||||||
BASS_SAMPLE_LOOP); // set the LOOP flag
|
|
||||||
if (m_loop_sync[channel] != 0)
|
|
||||||
{
|
{
|
||||||
BASS_ChannelRemoveSync(m_stream_list[channel],
|
if (BASS_ChannelFlags(m_stream_list[streamId], 0, 0) & BASS_SAMPLE_LOOP)
|
||||||
m_loop_sync[channel]); // remove the sync
|
{
|
||||||
m_loop_sync[channel] = 0;
|
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.
|
// 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
|
else
|
||||||
{
|
{
|
||||||
// Loop when the end of the file is reached.
|
// 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
|
class AOMusicPlayer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Channel 0 = music
|
// 0 = music
|
||||||
// Channel 1 = ambience
|
// 1 = ambience
|
||||||
static constexpr int CHANNEL_COUNT = 2;
|
static constexpr int STREAM_COUNT = 2;
|
||||||
|
|
||||||
AOMusicPlayer(AOApplication *p_ao_app);
|
explicit AOMusicPlayer(AOApplication *ao_app);
|
||||||
virtual ~AOMusicPlayer();
|
virtual ~AOMusicPlayer();
|
||||||
|
|
||||||
void set_volume(int p_value, int channel = -1);
|
void setMuted(bool enabled);
|
||||||
void set_looping(bool loop_song, int channel = 0);
|
|
||||||
void set_muted(bool toggle);
|
|
||||||
|
|
||||||
QFutureWatcher<QString> music_watcher;
|
QString playStream(QString song, int streamId, bool loopEnabled, int effectFlags);
|
||||||
|
|
||||||
public Q_SLOTS:
|
void setStreamVolume(int value, int streamId);
|
||||||
QString play(QString p_song, int channel = 0, bool loop = false, int effect_flags = 0);
|
void setStreamLooping(bool enabled, int streamId);
|
||||||
void stop(int channel = 0);
|
|
||||||
|
QFutureWatcher<QString> m_watcher;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AOApplication *ao_app;
|
AOApplication *ao_app;
|
||||||
|
|
||||||
bool m_muted = false;
|
bool m_muted = false;
|
||||||
int m_volume[CHANNEL_COUNT] = {0, 0};
|
|
||||||
HSTREAM m_stream_list[CHANNEL_COUNT];
|
|
||||||
HSYNC m_loop_sync[CHANNEL_COUNT];
|
|
||||||
|
|
||||||
/**
|
int m_volume[STREAM_COUNT]{};
|
||||||
* @brief The starting sample of the AB-Loop.
|
HSTREAM m_stream_list[STREAM_COUNT]{};
|
||||||
*/
|
HSYNC m_loop_sync[STREAM_COUNT]{};
|
||||||
unsigned int m_loop_start[CHANNEL_COUNT] = {0, 0};
|
quint32 m_loop_start[STREAM_COUNT]{};
|
||||||
|
quint32 m_loop_end[STREAM_COUNT]{};
|
||||||
|
|
||||||
/**
|
bool ensureValidStreamId(int streamId);
|
||||||
* @brief The end sample of the AB-Loop.
|
|
||||||
*/
|
|
||||||
unsigned int m_loop_end[CHANNEL_COUNT] = {0, 0};
|
|
||||||
};
|
};
|
||||||
|
@ -10,6 +10,9 @@ QString AOPacket::decode(QString data)
|
|||||||
return data.replace("<num>", "#").replace("<percent>", "%").replace("<dollar>", "$").replace("<and>", "&");
|
return data.replace("<num>", "#").replace("<percent>", "%").replace("<dollar>", "$").replace("<and>", "&");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AOPacket::AOPacket()
|
||||||
|
{}
|
||||||
|
|
||||||
AOPacket::AOPacket(QString header)
|
AOPacket::AOPacket(QString header)
|
||||||
: m_header(header)
|
: m_header(header)
|
||||||
{}
|
{}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QMetaType>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ public:
|
|||||||
static QString encode(QString data);
|
static QString encode(QString data);
|
||||||
static QString decode(QString data);
|
static QString decode(QString data);
|
||||||
|
|
||||||
|
AOPacket();
|
||||||
AOPacket(QString header);
|
AOPacket(QString header);
|
||||||
AOPacket(QString header, QStringList content);
|
AOPacket(QString header, QStringList content);
|
||||||
|
|
||||||
@ -21,3 +23,4 @@ private:
|
|||||||
QString m_header;
|
QString m_header;
|
||||||
QStringList m_content;
|
QStringList m_content;
|
||||||
};
|
};
|
||||||
|
Q_DECLARE_METATYPE(AOPacket)
|
||||||
|
@ -2,111 +2,135 @@
|
|||||||
|
|
||||||
#include "file_functions.h"
|
#include "file_functions.h"
|
||||||
|
|
||||||
AOSfxPlayer::AOSfxPlayer(AOApplication *p_ao_app)
|
AOSfxPlayer::AOSfxPlayer(AOApplication *ao_app)
|
||||||
: ao_app(p_ao_app)
|
: ao_app(ao_app)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void AOSfxPlayer::clear()
|
int AOSfxPlayer::volume()
|
||||||
{
|
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
return m_volume * 100;
|
return m_volume * 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOSfxPlayer::set_volume(qreal p_value)
|
void AOSfxPlayer::setVolume(int value)
|
||||||
{
|
{
|
||||||
m_volume = p_value * 0.01;
|
m_volume = value;
|
||||||
set_volume_internal(m_volume);
|
updateInternalVolume();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AOSfxPlayer::set_volume_internal(qreal p_value)
|
void AOSfxPlayer::play(QString path)
|
||||||
{
|
{
|
||||||
// If muted, volume will always be 0
|
for (int i = 0; i < STREAM_COUNT; ++i)
|
||||||
float volume = static_cast<float>(p_value) * !m_muted;
|
|
||||||
for (int n_stream = 0; n_stream < CHANNEL_COUNT; ++n_stream)
|
|
||||||
{
|
{
|
||||||
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;
|
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)
|
if (m_looping == false)
|
||||||
{
|
{
|
||||||
BASS_ChannelFlags(m_stream_list[channel], 0,
|
BASS_ChannelFlags(m_stream[streamId], 0,
|
||||||
BASS_SAMPLE_LOOP); // remove the LOOP flag
|
BASS_SAMPLE_LOOP); // remove the LOOP flag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,8 +138,18 @@ void AOSfxPlayer::set_looping(bool toggle, int channel)
|
|||||||
{
|
{
|
||||||
if (m_looping == true)
|
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
|
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
|
class AOSfxPlayer
|
||||||
{
|
{
|
||||||
public:
|
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 play(QString path);
|
||||||
void loop_clear();
|
void stop(int streamId = -1);
|
||||||
void play(QString p_sfx, QString p_char = QString(), QString shout = QString());
|
void stopAll();
|
||||||
void stop(int channel = -1);
|
void stopAllLoopingStream();
|
||||||
void set_volume(qreal p_volume);
|
|
||||||
void set_looping(bool toggle, int channel = -1);
|
void findAndPlaySfx(QString sfx);
|
||||||
void set_muted(bool toggle);
|
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:
|
private:
|
||||||
AOApplication *ao_app;
|
AOApplication *ao_app;
|
||||||
|
|
||||||
qreal m_volume = 0.0;
|
int m_volume = 0;
|
||||||
bool m_looping = true;
|
|
||||||
bool m_muted = false;
|
bool m_muted = false;
|
||||||
int m_channel = 0;
|
bool m_looping = true;
|
||||||
HSTREAM m_stream_list[CHANNEL_COUNT]{};
|
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"
|
#include "aotextarea.h"
|
||||||
|
|
||||||
AOTextArea::AOTextArea(QWidget *p_parent)
|
AOTextArea::AOTextArea(QWidget *parent)
|
||||||
: AOTextArea(5000, p_parent)
|
: AOTextArea(5000, parent)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
AOTextArea::AOTextArea(int p_log_length, QWidget *p_parent)
|
AOTextArea::AOTextArea(int maximumLogLenth, QWidget *parent)
|
||||||
: QTextBrowser(p_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 QTextCursor old_cursor = this->textCursor();
|
||||||
const int old_scrollbar_value = this->verticalScrollBar()->value();
|
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->moveCursor(QTextCursor::End);
|
||||||
|
|
||||||
this->append("");
|
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
|
// 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);
|
this->insertHtml(result);
|
||||||
|
@ -11,10 +11,10 @@ class AOTextArea : public QTextBrowser
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AOTextArea(QWidget *p_parent = nullptr);
|
AOTextArea(QWidget *parent = nullptr);
|
||||||
AOTextArea(int p_log_length, QWidget *p_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:
|
private:
|
||||||
const QRegularExpression url_parser_regex = QRegularExpression("\\b(https?://\\S+\\.\\S+)\\b");
|
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
|
// 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.
|
// 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++;
|
ao_app->generated_chars++;
|
||||||
}
|
}
|
||||||
|
@ -28,20 +28,20 @@ Courtroom::Courtroom(AOApplication *p_ao_app)
|
|||||||
sfx_delay_timer->setSingleShot(true);
|
sfx_delay_timer->setSingleShot(true);
|
||||||
|
|
||||||
music_player = new AOMusicPlayer(ao_app);
|
music_player = new AOMusicPlayer(ao_app);
|
||||||
music_player->set_muted(true);
|
music_player->setMuted(true);
|
||||||
connect(&music_player->music_watcher, &QFutureWatcher<QString>::finished, this, &Courtroom::update_ui_music_name, Qt::QueuedConnection);
|
connect(&music_player->m_watcher, &QFutureWatcher<QString>::finished, this, &Courtroom::update_ui_music_name, Qt::QueuedConnection);
|
||||||
|
|
||||||
sfx_player = new AOSfxPlayer(ao_app);
|
sfx_player = new AOSfxPlayer(ao_app);
|
||||||
sfx_player->set_muted(true);
|
sfx_player->setMuted(true);
|
||||||
|
|
||||||
objection_player = new AOSfxPlayer(ao_app);
|
objection_player = new AOSfxPlayer(ao_app);
|
||||||
objection_player->set_muted(true);
|
objection_player->setMuted(true);
|
||||||
|
|
||||||
blip_player = new AOBlipPlayer(ao_app);
|
blip_player = new AOBlipPlayer(ao_app);
|
||||||
blip_player->set_muted(true);
|
blip_player->setMuted(true);
|
||||||
|
|
||||||
modcall_player = new AOSfxPlayer(ao_app);
|
modcall_player = new AOSfxPlayer(ao_app);
|
||||||
modcall_player->set_volume(50);
|
modcall_player->setVolume(50);
|
||||||
|
|
||||||
ui_background = new AOImage(ao_app, this);
|
ui_background = new AOImage(ao_app, this);
|
||||||
ui_background->setObjectName("ui_background");
|
ui_background->setObjectName("ui_background");
|
||||||
@ -552,15 +552,15 @@ void Courtroom::update_audio_volume()
|
|||||||
remaining_percent = 0;
|
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
|
// 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);
|
sfx_player->setVolume(ui_sfx_slider->value() * remaining_percent);
|
||||||
objection_player->set_volume(ui_sfx_slider->value() * remaining_percent);
|
objection_player->setVolume(ui_sfx_slider->value() * remaining_percent);
|
||||||
blip_player->set_volume(ui_blip_slider->value() * remaining_percent);
|
blip_player->setVolume(ui_blip_slider->value() * remaining_percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Courtroom::append_char(CharacterSlot p_char)
|
void Courtroom::append_char(CharacterSlot p_char)
|
||||||
@ -1688,10 +1688,10 @@ void Courtroom::enter_courtroom()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unmute everything
|
// Unmute everything
|
||||||
music_player->set_muted(false);
|
music_player->setMuted(false);
|
||||||
objection_player->set_muted(false);
|
objection_player->setMuted(false);
|
||||||
sfx_player->set_muted(false);
|
sfx_player->setMuted(false);
|
||||||
blip_player->set_muted(false);
|
blip_player->setMuted(false);
|
||||||
|
|
||||||
// Update the audio sliders
|
// Update the audio sliders
|
||||||
update_audio_volume();
|
update_audio_volume();
|
||||||
@ -1866,7 +1866,7 @@ void Courtroom::debug_message_handler(QtMsgType type, const QMessageLogContext &
|
|||||||
Q_UNUSED(context);
|
Q_UNUSED(context);
|
||||||
const QMap<QtMsgType, QString> colors = {{QtDebugMsg, "debug"}, {QtInfoMsg, "info"}, {QtWarningMsg, "warn"}, {QtCriticalMsg, "critical"}, {QtFatalMsg, "fatal"}};
|
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"));
|
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)
|
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);
|
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())
|
if (Options::getInstance().logToTextFileEnabled() && !ao_app->log_filename.isEmpty())
|
||||||
{
|
{
|
||||||
@ -2666,33 +2666,33 @@ bool Courtroom::handle_objection()
|
|||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
filename = "holdit_bubble";
|
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;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
filename = "objection_bubble";
|
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;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
filename = "takethat_bubble";
|
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;
|
break;
|
||||||
// case 4 is AO2 only
|
// case 4 is AO2 only
|
||||||
case 4:
|
case 4:
|
||||||
if (custom_objection != "")
|
if (custom_objection != "")
|
||||||
{
|
{
|
||||||
filename = "custom_objections/" + custom_objection.left(custom_objection.lastIndexOf("."));
|
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
|
else
|
||||||
{
|
{
|
||||||
filename = "custom";
|
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;
|
break;
|
||||||
m_chatmessage[EMOTE_MOD] = QChar(PREANIM);
|
m_chatmessage[EMOTE_MOD] = QChar(PREANIM);
|
||||||
}
|
}
|
||||||
ui_vp_objection->load_image(filename, m_chatmessage[CHAR_NAME], ao_app->get_chat(m_chatmessage[CHAR_NAME]));
|
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);
|
ui_vp_player_char->set_play_once(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2710,7 +2710,7 @@ void Courtroom::display_character()
|
|||||||
ui_vp_player_char->stop();
|
ui_vp_player_char->stop();
|
||||||
ui_vp_effect->stop();
|
ui_vp_effect->stop();
|
||||||
// Clear all looping sfx to prevent obnoxiousness
|
// Clear all looping sfx to prevent obnoxiousness
|
||||||
sfx_player->loop_clear();
|
sfx_player->stopAllLoopingStream();
|
||||||
// Hide the message and chatbox and handle the emotes
|
// Hide the message and chatbox and handle the emotes
|
||||||
ui_vp_message->hide();
|
ui_vp_message->hide();
|
||||||
ui_vp_chatbox->setVisible(chatbox_always_show);
|
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 != "")
|
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
|
// 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)
|
void Courtroom::play_char_sfx(QString sfx_name)
|
||||||
{
|
{
|
||||||
sfx_player->play(sfx_name);
|
sfx_player->findAndPlaySfx(sfx_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Courtroom::initialize_chatbox()
|
void Courtroom::initialize_chatbox()
|
||||||
@ -3216,7 +3216,7 @@ void Courtroom::handle_callwords()
|
|||||||
if (f_message.contains(word, Qt::CaseInsensitive))
|
if (f_message.contains(word, Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
// Play the call word sfx on the modcall_player sound container
|
// 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
|
// Make the window flash
|
||||||
ao_app->alert(this);
|
ao_app->alert(this);
|
||||||
// Break the loop so we don't spam sound effects
|
// 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;
|
// 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
|
// 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");
|
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")
|
else if (m_chatmessage[REALIZATION] == "1")
|
||||||
{
|
{
|
||||||
this->do_flash();
|
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
|
int emote_mod = m_chatmessage[EMOTE_MOD].toInt(); // text meme bonanza
|
||||||
if ((emote_mod == IDLE || emote_mod == ZOOM) && m_chatmessage[SCREENSHAKE] == "1")
|
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]);
|
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
|
// means text is currently ticking
|
||||||
text_state = 1;
|
text_state = 1;
|
||||||
@ -4276,7 +4276,7 @@ void Courtroom::chat_tick()
|
|||||||
// ignoring white space unless blank_blip is enabled.
|
// ignoring white space unless blank_blip is enabled.
|
||||||
if (!formatting_char && (f_character != ' ' || blank_blip))
|
if (!formatting_char && (f_character != ' ' || blank_blip))
|
||||||
{
|
{
|
||||||
blip_player->blip_tick();
|
blip_player->playBlip();
|
||||||
++blip_ticker;
|
++blip_ticker;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4335,10 +4335,10 @@ void Courtroom::play_sfx()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sfx_player->play(sfx_name);
|
sfx_player->findAndPlaySfx(sfx_name);
|
||||||
if (Options::getInstance().loopingSfx())
|
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.
|
// Current song UI only displays the song playing, not other channels.
|
||||||
// Any other music playing is irrelevant.
|
// 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));
|
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));
|
music_player->m_watcher.setFuture(QtConcurrent::run([=, this]() -> QString { return music_player->playStream(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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Courtroom::update_ui_music_name()
|
void Courtroom::update_ui_music_name()
|
||||||
{
|
{
|
||||||
QString result = music_player->music_watcher.result();
|
QString result = music_player->m_watcher.result();
|
||||||
if (result.isEmpty())
|
if (result.isEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -4590,7 +4587,7 @@ void Courtroom::handle_wtce(QString p_wtce, int variant)
|
|||||||
filename = p_wtce;
|
filename = p_wtce;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sfx_player->play(sfx_name);
|
sfx_player->findAndPlaySfx(sfx_name);
|
||||||
ui_vp_wtce->load_image(filename, "", bg_misc);
|
ui_vp_wtce->load_image(filename, "", bg_misc);
|
||||||
ui_vp_wtce->set_play_once(true);
|
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())
|
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);
|
ui_server_chatlog->append(p_ip);
|
||||||
if (!ui_guard->isChecked())
|
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);
|
ao_app->alert(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4703,11 +4700,7 @@ void Courtroom::on_ooc_return_pressed()
|
|||||||
|
|
||||||
if (ooc_message.startsWith("/load_case"))
|
if (ooc_message.startsWith("/load_case"))
|
||||||
{
|
{
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
QStringList command = ooc_message.split(" ", AOSplitBehaviorFlags::SkipEmptyParts);
|
||||||
QStringList command = ooc_message.split(" ", QString::SkipEmptyParts);
|
|
||||||
#else
|
|
||||||
QStringList command = ooc_message.split(" ", Qt::SkipEmptyParts);
|
|
||||||
#endif
|
|
||||||
QDir casefolder(get_base_path() + "/cases");
|
QDir casefolder(get_base_path() + "/cases");
|
||||||
if (!casefolder.exists())
|
if (!casefolder.exists())
|
||||||
{
|
{
|
||||||
@ -4803,11 +4796,7 @@ void Courtroom::on_ooc_return_pressed()
|
|||||||
}
|
}
|
||||||
else if (ooc_message.startsWith("/save_case"))
|
else if (ooc_message.startsWith("/save_case"))
|
||||||
{
|
{
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
QStringList command = ooc_message.split(" ", AOSplitBehaviorFlags::SkipEmptyParts);
|
||||||
QStringList command = ooc_message.split(" ", QString::SkipEmptyParts);
|
|
||||||
#else
|
|
||||||
QStringList command = ooc_message.split(" ", Qt::SkipEmptyParts);
|
|
||||||
#endif
|
|
||||||
QDir casefolder(get_base_path() + "cases");
|
QDir casefolder(get_base_path() + "cases");
|
||||||
if (!casefolder.exists())
|
if (!casefolder.exists())
|
||||||
{
|
{
|
||||||
@ -5265,7 +5254,7 @@ void Courtroom::on_sfx_context_menu_requested(const QPoint &pos)
|
|||||||
|
|
||||||
void Courtroom::on_sfx_play_clicked()
|
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()
|
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)
|
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();
|
ui_ic_chat_message->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Courtroom::on_sfx_slider_moved(int p_value)
|
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
|
// 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();
|
ui_ic_chat_message->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Courtroom::on_blip_slider_moved(int p_value)
|
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();
|
ui_ic_chat_message->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6150,8 +6139,8 @@ void Courtroom::on_guilty_clicked()
|
|||||||
|
|
||||||
void Courtroom::on_change_character_clicked()
|
void Courtroom::on_change_character_clicked()
|
||||||
{
|
{
|
||||||
sfx_player->set_muted(true);
|
sfx_player->setMuted(true);
|
||||||
blip_player->set_muted(true);
|
blip_player->setMuted(true);
|
||||||
|
|
||||||
set_char_select();
|
set_char_select();
|
||||||
|
|
||||||
|
@ -3,6 +3,12 @@
|
|||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||||
|
using AOSplitBehaviorFlags = QString::SplitBehaviorFlags;
|
||||||
|
#else
|
||||||
|
using AOSplitBehaviorFlags = Qt::SplitBehaviorFlags;
|
||||||
|
#endif
|
||||||
|
|
||||||
enum ServerConnectionType
|
enum ServerConnectionType
|
||||||
{
|
{
|
||||||
TcpServerConnection,
|
TcpServerConnection,
|
||||||
@ -18,6 +24,8 @@ struct ServerInfo
|
|||||||
QString ip;
|
QString ip;
|
||||||
int port;
|
int port;
|
||||||
ServerConnectionType socket_type;
|
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
|
struct CharacterSlot
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "demoserver.h"
|
#include "demoserver.h"
|
||||||
|
|
||||||
|
#include "datatypes.h"
|
||||||
|
|
||||||
DemoServer::DemoServer(QObject *parent)
|
DemoServer::DemoServer(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
@ -93,12 +95,7 @@ void DemoServer::recv_data()
|
|||||||
{
|
{
|
||||||
QString in_data = QString::fromUtf8(client_sock->readAll());
|
QString in_data = QString::fromUtf8(client_sock->readAll());
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
const QStringList packet_list = in_data.split("%", AOSplitBehaviorFlags::SkipEmptyParts);
|
||||||
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)
|
for (const QString &packet : packet_list)
|
||||||
{
|
{
|
||||||
QStringList f_contents;
|
QStringList f_contents;
|
||||||
|
@ -22,6 +22,7 @@ void Courtroom::initialize_emotes()
|
|||||||
|
|
||||||
emote_preview = new AOEmotePreview(ao_app, this);
|
emote_preview = new AOEmotePreview(ao_app, this);
|
||||||
emote_preview->setObjectName("ui_emote_preview");
|
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_left, &AOButton::clicked, this, &Courtroom::on_emote_left_clicked);
|
||||||
connect(ui_emote_right, &AOButton::clicked, this, &Courtroom::on_emote_right_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_menu->setDefaultAction(emote_menu->addAction("Preview Selected", this, [this] {
|
||||||
emote_preview->show();
|
emote_preview->show();
|
||||||
emote_preview->raise();
|
emote_preview->raise();
|
||||||
emote_preview->set_widgets();
|
emote_preview->updateViewportGeometry();
|
||||||
update_emote_preview();
|
update_emote_preview();
|
||||||
}));
|
}));
|
||||||
QString prefix;
|
QString prefix;
|
||||||
@ -291,8 +292,8 @@ void Courtroom::preview_emote(QString f_emote)
|
|||||||
{
|
{
|
||||||
emote_preview->show();
|
emote_preview->show();
|
||||||
emote_preview->raise();
|
emote_preview->raise();
|
||||||
emote_preview->set_widgets();
|
emote_preview->updateViewportGeometry();
|
||||||
emote_preview->play(f_emote, current_char, ui_flip->isChecked(), ui_pair_offset_spinbox->value(), ui_pair_vert_offset_spinbox->value());
|
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()
|
void Courtroom::on_emote_left_clicked()
|
||||||
|
@ -17,6 +17,8 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
qSetMessagePattern("%{type}: %{if-category}%{category}: %{endif}%{message}");
|
qSetMessagePattern("%{type}: %{if-category}%{category}: %{endif}%{message}");
|
||||||
|
|
||||||
|
qRegisterMetaType<AOPacket>();
|
||||||
|
|
||||||
AOApplication main_app(argc, argv);
|
AOApplication main_app(argc, argv);
|
||||||
|
|
||||||
#ifdef ANDROID
|
#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 "datatypes.h"
|
||||||
#include "debug_functions.h"
|
#include "debug_functions.h"
|
||||||
#include "lobby.h"
|
#include "lobby.h"
|
||||||
|
#include "net/nettcpconnection.h"
|
||||||
|
#include "net/netwebsocketconnection.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
|
||||||
#include <QAbstractSocket>
|
#include <QAbstractSocket>
|
||||||
@ -77,13 +79,18 @@ void NetworkManager::ms_request_finished(QNetworkReply *reply)
|
|||||||
}
|
}
|
||||||
ao_app->set_server_list(server_list);
|
ao_app->set_server_list(server_list);
|
||||||
|
|
||||||
if (ao_app->lobby_constructed)
|
if (ao_app->is_lobby_constructed())
|
||||||
{
|
{
|
||||||
ao_app->w_lobby->list_servers();
|
ao_app->w_lobby->list_servers();
|
||||||
}
|
}
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString NetworkManager::get_user_agent() const
|
||||||
|
{
|
||||||
|
return QStringLiteral("AttorneyOnline/%1 (Desktop)").arg(ao_app->get_version_string());
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkManager::send_heartbeat()
|
void NetworkManager::send_heartbeat()
|
||||||
{
|
{
|
||||||
// Ping the server periodically to tell the MS that you've been playing
|
// 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();
|
disconnect_from_server();
|
||||||
|
|
||||||
qInfo().nospace().noquote() << "connecting to " << p_server.ip << ":" << p_server.port;
|
qInfo().noquote() << QObject::tr("Connecting to %1").arg(server.toString());
|
||||||
|
switch (server.socket_type)
|
||||||
switch (p_server.socket_type)
|
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
p_server.socket_type = TcpServerConnection;
|
server.socket_type = TcpServerConnection;
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
|
||||||
case TcpServerConnection:
|
case TcpServerConnection:
|
||||||
qInfo() << "using TCP backend";
|
qInfo() << "Using TCP backend.";
|
||||||
server_socket.tcp = new QTcpSocket(this);
|
m_connection = new NetTcpConnection(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);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WebSocketServerConnection:
|
case WebSocketServerConnection:
|
||||||
qInfo() << "using WebSockets backend";
|
qInfo() << "Using WebSockets backend.";
|
||||||
server_socket.ws = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this);
|
m_connection = new NetWebSocketConnection(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);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
connected = true;
|
connect(m_connection, &NetConnection::connectedToServer, this, [] { qInfo() << "Established connection to server."; });
|
||||||
active_connection_type = p_server.socket_type;
|
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()
|
void NetworkManager::join_to_server()
|
||||||
@ -195,98 +207,8 @@ void NetworkManager::join_to_server()
|
|||||||
ship_server_packet(AOPacket("askchaa").toString());
|
ship_server_packet(AOPacket("askchaa").toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkManager::disconnect_from_server()
|
void NetworkManager::handle_server_packet(AOPacket packet)
|
||||||
{
|
{
|
||||||
if (!connected)
|
qInfo().noquote() << "Received packet:" << packet.toString();
|
||||||
{
|
ao_app->server_packet_received(packet);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "aoapplication.h"
|
#include "aoapplication.h"
|
||||||
#include "aopacket.h"
|
#include "aopacket.h"
|
||||||
|
#include "net/netconnection.h"
|
||||||
|
|
||||||
#include <QDnsLookup>
|
#include <QDnsLookup>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
@ -28,11 +29,13 @@ public:
|
|||||||
void connect_to_server(ServerInfo p_server);
|
void connect_to_server(ServerInfo p_server);
|
||||||
void disconnect_from_server();
|
void disconnect_from_server();
|
||||||
|
|
||||||
|
QString get_user_agent() const;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void get_server_list();
|
void get_server_list();
|
||||||
void ship_server_packet(AOPacket p_packet);
|
void ship_server_packet(AOPacket packet);
|
||||||
void join_to_server();
|
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 request_document(MSDocumentType document_type, const std::function<void(QString)> &cb);
|
||||||
void send_heartbeat();
|
void send_heartbeat();
|
||||||
@ -47,13 +50,7 @@ private:
|
|||||||
AOApplication *ao_app;
|
AOApplication *ao_app;
|
||||||
QNetworkAccessManager *http;
|
QNetworkAccessManager *http;
|
||||||
|
|
||||||
union
|
NetConnection *m_connection = nullptr;
|
||||||
{
|
|
||||||
QWebSocket *ws;
|
|
||||||
QTcpSocket *tcp;
|
|
||||||
} server_socket;
|
|
||||||
ServerConnectionType active_connection_type;
|
|
||||||
bool connected = false;
|
|
||||||
|
|
||||||
QTimer *heartbeat_timer;
|
QTimer *heartbeat_timer;
|
||||||
|
|
||||||
@ -62,10 +59,5 @@ private:
|
|||||||
|
|
||||||
const int heartbeat_interval = 60 * 5 * 1000;
|
const int heartbeat_interval = 60 * 5 * 1000;
|
||||||
|
|
||||||
bool partial_packet = false;
|
|
||||||
QString temp_packet;
|
|
||||||
|
|
||||||
unsigned int s_decryptor = 5;
|
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 header = packet.header();
|
||||||
QString f_packet_encoded = p_packet.toString();
|
QStringList content = packet.content();
|
||||||
|
|
||||||
QString header = p_packet.header();
|
|
||||||
QStringList f_contents = p_packet.content();
|
|
||||||
QString f_packet = p_packet.toString();
|
|
||||||
|
|
||||||
bool log_to_demo = true;
|
bool log_to_demo = true;
|
||||||
|
|
||||||
@ -44,7 +40,7 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
|
|
||||||
if (header == "decryptor")
|
if (header == "decryptor")
|
||||||
{
|
{
|
||||||
if (f_contents.size() == 0)
|
if (content.size() == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -76,13 +72,13 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
else if (header == "ID")
|
else if (header == "ID")
|
||||||
{
|
{
|
||||||
if (f_contents.size() < 2)
|
if (content.size() < 2)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
client_id = f_contents.at(0).toInt();
|
client_id = content.at(0).toInt();
|
||||||
server_software = f_contents.at(1);
|
server_software = content.at(1);
|
||||||
|
|
||||||
net_manager->server_connected(true);
|
net_manager->server_connected(true);
|
||||||
|
|
||||||
@ -91,18 +87,18 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
else if (header == "CT")
|
else if (header == "CT")
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed || f_contents.size() < 2)
|
if (!is_courtroom_constructed() || content.size() < 2)
|
||||||
{
|
{
|
||||||
return;
|
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
|
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")
|
else if (header == "FL")
|
||||||
@ -125,104 +121,102 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
custom_blips_supported = false;
|
custom_blips_supported = false;
|
||||||
log_to_demo = false;
|
log_to_demo = false;
|
||||||
|
|
||||||
if (f_packet.contains("yellowtext", Qt::CaseInsensitive))
|
if (content.contains("yellowtext", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
yellow_text_supported = true;
|
yellow_text_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("prezoom", Qt::CaseInsensitive))
|
if (content.contains("prezoom", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
prezoom_supported = true;
|
prezoom_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("flipping", Qt::CaseInsensitive))
|
if (content.contains("flipping", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
flipping_supported = true;
|
flipping_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("customobjections", Qt::CaseInsensitive))
|
if (content.contains("customobjections", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
custom_objection_supported = true;
|
custom_objection_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("deskmod", Qt::CaseInsensitive))
|
if (content.contains("deskmod", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
desk_mod_supported = true;
|
desk_mod_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("evidence", Qt::CaseInsensitive))
|
if (content.contains("evidence", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
evidence_supported = true;
|
evidence_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("cccc_ic_support", Qt::CaseInsensitive))
|
if (content.contains("cccc_ic_support", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
cccc_ic_supported = true;
|
cccc_ic_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("arup", Qt::CaseInsensitive))
|
if (content.contains("arup", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
arup_supported = true;
|
arup_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("casing_alerts", Qt::CaseInsensitive))
|
if (content.contains("casing_alerts", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
casing_alerts_supported = true;
|
casing_alerts_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("modcall_reason", Qt::CaseInsensitive))
|
if (content.contains("modcall_reason", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
modcall_reason_supported = true;
|
modcall_reason_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("looping_sfx", Qt::CaseInsensitive))
|
if (content.contains("looping_sfx", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
looping_sfx_supported = true;
|
looping_sfx_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("additive", Qt::CaseInsensitive))
|
if (content.contains("additive", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
additive_supported = true;
|
additive_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("effects", Qt::CaseInsensitive))
|
if (content.contains("effects", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
effects_supported = true;
|
effects_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("y_offset", Qt::CaseInsensitive))
|
if (content.contains("y_offset", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
y_offset_supported = true;
|
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;
|
expanded_desk_mods_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("auth_packet", Qt::CaseInsensitive))
|
if (content.contains("auth_packet", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
auth_packet_supported = true;
|
auth_packet_supported = true;
|
||||||
}
|
}
|
||||||
if (f_packet.contains("custom_blips", Qt::CaseInsensitive))
|
if (content.contains("custom_blips", Qt::CaseInsensitive))
|
||||||
{
|
{
|
||||||
custom_blips_supported = true;
|
custom_blips_supported = true;
|
||||||
}
|
}
|
||||||
log_to_demo = false;
|
log_to_demo = false;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (header == "PN")
|
else if (header == "PN")
|
||||||
{
|
{
|
||||||
if (!lobby_constructed || f_contents.size() < 2)
|
if (!is_lobby_constructed() || content.size() < 2)
|
||||||
{
|
{
|
||||||
return;
|
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;
|
log_to_demo = false;
|
||||||
}
|
}
|
||||||
else if (header == "SI")
|
else if (header == "SI")
|
||||||
{
|
{
|
||||||
if (!lobby_constructed || f_contents.size() != 3)
|
if (!is_lobby_constructed() || content.size() != 3)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char_list_size = f_contents.at(0).toInt();
|
char_list_size = content.at(0).toInt();
|
||||||
evidence_list_size = f_contents.at(1).toInt();
|
evidence_list_size = content.at(1).toInt();
|
||||||
music_list_size = f_contents.at(2).toInt();
|
music_list_size = content.at(2).toInt();
|
||||||
|
|
||||||
if (char_list_size < 0 || evidence_list_size < 0 || music_list_size < 0)
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (courtroom_constructed)
|
if (is_courtroom_constructed())
|
||||||
{
|
{
|
||||||
w_courtroom->set_window_title(window_title);
|
w_courtroom->set_window_title(window_title);
|
||||||
}
|
}
|
||||||
@ -301,14 +295,14 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
else if (header == "CharsCheck")
|
else if (header == "CharsCheck")
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed)
|
if (!is_courtroom_constructed())
|
||||||
{
|
{
|
||||||
return;
|
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);
|
w_courtroom->set_taken(n_char, true);
|
||||||
}
|
}
|
||||||
@ -322,14 +316,14 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
|
|
||||||
else if (header == "SC")
|
else if (header == "SC")
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed)
|
if (!is_courtroom_constructed())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
w_courtroom->clear_chars();
|
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)
|
for (QString &sub_element : sub_elements)
|
||||||
{
|
{
|
||||||
sub_element = AOPacket::decode(sub_element);
|
sub_element = AOPacket::decode(sub_element);
|
||||||
@ -359,7 +353,7 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
else if (header == "SM")
|
else if (header == "SM")
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed || courtroom_loaded)
|
if (!is_courtroom_constructed() || courtroom_loaded)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -367,25 +361,25 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
bool musics_time = false;
|
bool musics_time = false;
|
||||||
int areas = 0;
|
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;
|
++loaded_music;
|
||||||
if (musics_time)
|
if (musics_time)
|
||||||
{
|
{
|
||||||
w_courtroom->append_music(f_contents.at(n_element));
|
w_courtroom->append_music(content.at(n_element));
|
||||||
}
|
}
|
||||||
else
|
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;
|
musics_time = true;
|
||||||
w_courtroom->fix_last_area();
|
w_courtroom->fix_last_area();
|
||||||
w_courtroom->append_music(f_contents.at(n_element));
|
w_courtroom->append_music(content.at(n_element));
|
||||||
areas--;
|
areas--;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
w_courtroom->append_area(f_contents.at(n_element));
|
w_courtroom->append_area(content.at(n_element));
|
||||||
areas++;
|
areas++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -401,16 +395,16 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
else if (header == "FM") // Fetch music ONLY
|
else if (header == "FM") // Fetch music ONLY
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed)
|
if (!is_courtroom_constructed())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
w_courtroom->clear_music();
|
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();
|
w_courtroom->list_music();
|
||||||
@ -418,7 +412,7 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
else if (header == "FA") // Fetch areas ONLY
|
else if (header == "FA") // Fetch areas ONLY
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed)
|
if (!is_courtroom_constructed())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -426,9 +420,9 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
w_courtroom->clear_areas();
|
w_courtroom->clear_areas();
|
||||||
w_courtroom->arup_clear();
|
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");
|
w_courtroom->arup_append(0, "Unknown", "Unknown", "Unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,7 +431,7 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
else if (header == "DONE")
|
else if (header == "DONE")
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed)
|
if (!is_courtroom_constructed())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -452,99 +446,99 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
else if (header == "BN")
|
else if (header == "BN")
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed || f_contents.isEmpty())
|
if (!is_courtroom_constructed() || content.isEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f_contents.size() >= 2)
|
if (content.size() >= 2)
|
||||||
{
|
{
|
||||||
// We have a pos included in the background packet!
|
// 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.
|
// 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")
|
else if (header == "SP")
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed || f_contents.isEmpty())
|
if (!is_courtroom_constructed() || content.isEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We were sent a "set position" packet
|
// 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
|
else if (header == "SD") // Send pos dropdown
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed || f_contents.isEmpty())
|
if (!is_courtroom_constructed() || content.isEmpty())
|
||||||
{
|
{
|
||||||
return;
|
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
|
// server accepting char request(CC) packet
|
||||||
else if (header == "PV")
|
else if (header == "PV")
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed || f_contents.size() < 3)
|
if (!is_courtroom_constructed() || content.size() < 3)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// For some reason, args 0 and 1 are not used (from tsu3 they're client ID and a string "CID")
|
// 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->enter_courtroom();
|
||||||
w_courtroom->set_courtroom_size();
|
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")
|
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")
|
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")
|
else if (header == "RT")
|
||||||
{
|
{
|
||||||
if (f_contents.isEmpty())
|
if (content.isEmpty())
|
||||||
{
|
{
|
||||||
return;
|
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")
|
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")
|
else if (header == "LE")
|
||||||
{
|
{
|
||||||
if (courtroom_constructed)
|
if (is_courtroom_constructed())
|
||||||
{
|
{
|
||||||
QVector<EvidenceItem> f_evi_list;
|
QVector<EvidenceItem> f_evi_list;
|
||||||
|
|
||||||
for (QString f_string : f_contents_encoded)
|
for (QString f_string : packet.content())
|
||||||
{
|
{
|
||||||
QStringList sub_contents = f_string.split("&");
|
QStringList sub_contents = f_string.split("&");
|
||||||
if (sub_contents.size() < 3)
|
if (sub_contents.size() < 3)
|
||||||
@ -572,12 +566,12 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
else if (header == "ARUP")
|
else if (header == "ARUP")
|
||||||
{
|
{
|
||||||
if (courtroom_constructed && !f_contents.isEmpty())
|
if (is_courtroom_constructed() && !content.isEmpty())
|
||||||
{
|
{
|
||||||
int arup_type = f_contents.at(0).toInt();
|
int arup_type = content.at(0).toInt();
|
||||||
for (int n_element = 1; n_element < f_contents.size(); n_element++)
|
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();
|
w_courtroom->list_areas();
|
||||||
}
|
}
|
||||||
@ -585,41 +579,41 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
else if (header == "IL")
|
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;
|
log_to_demo = false;
|
||||||
}
|
}
|
||||||
else if (header == "MU")
|
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;
|
log_to_demo = false;
|
||||||
}
|
}
|
||||||
else if (header == "UM")
|
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;
|
log_to_demo = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (header == "BB")
|
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;
|
log_to_demo = false;
|
||||||
}
|
}
|
||||||
else if (header == "KK")
|
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();
|
construct_lobby();
|
||||||
destruct_courtroom();
|
destruct_courtroom();
|
||||||
}
|
}
|
||||||
@ -627,9 +621,9 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
else if (header == "KB")
|
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();
|
construct_lobby();
|
||||||
destruct_courtroom();
|
destruct_courtroom();
|
||||||
}
|
}
|
||||||
@ -637,46 +631,46 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
else if (header == "BD")
|
else if (header == "BD")
|
||||||
{
|
{
|
||||||
if (f_contents.isEmpty())
|
if (content.isEmpty())
|
||||||
{
|
{
|
||||||
return;
|
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;
|
log_to_demo = false;
|
||||||
}
|
}
|
||||||
else if (header == "ZZ")
|
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")
|
else if (header == "TI")
|
||||||
{ // Timer packet
|
{ // Timer packet
|
||||||
if (!courtroom_constructed || f_contents.size() < 2)
|
if (!is_courtroom_constructed() || content.size() < 2)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer ID is reserved as argument 0
|
// 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 0 = start/resume/sync timer at time
|
||||||
// Type 1 = pause timer at time
|
// Type 1 = pause timer at time
|
||||||
// Type 2 = show timer
|
// Type 2 = show timer
|
||||||
// Type 3 = hide timer
|
// Type 3 = hide timer
|
||||||
int type = f_contents.at(1).toInt();
|
int type = content.at(1).toInt();
|
||||||
|
|
||||||
if (type == 0 || type == 1)
|
if (type == 0 || type == 1)
|
||||||
{
|
{
|
||||||
if (f_contents.size() < 3)
|
if (content.size() < 3)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The time as displayed on the clock, in milliseconds.
|
// The time as displayed on the clock, in milliseconds.
|
||||||
// If the number received is negative, stop the timer.
|
// 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 (timer_value > 0)
|
||||||
{
|
{
|
||||||
if (type == 0)
|
if (type == 0)
|
||||||
@ -706,7 +700,7 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
else if (header == "CHECK")
|
else if (header == "CHECK")
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed)
|
if (!is_courtroom_constructed())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -722,12 +716,12 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
// Subtheme packet
|
// Subtheme packet
|
||||||
else if (header == "ST")
|
else if (header == "ST")
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed || f_contents.isEmpty())
|
if (!is_courtroom_constructed() || content.isEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Subtheme reserved as argument 0
|
// Subtheme reserved as argument 0
|
||||||
subtheme = f_contents.at(0);
|
subtheme = content.at(0);
|
||||||
|
|
||||||
// Check if we have subthemes set to "server"
|
// Check if we have subthemes set to "server"
|
||||||
if (Options::getInstance().settingsSubTheme().toLower() != "server")
|
if (Options::getInstance().settingsSubTheme().toLower() != "server")
|
||||||
@ -737,7 +731,7 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reload theme request
|
// 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);
|
Options::getInstance().setServerSubTheme(subtheme);
|
||||||
w_courtroom->on_reload_theme_clicked();
|
w_courtroom->on_reload_theme_clicked();
|
||||||
@ -746,15 +740,15 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
// Auth packet
|
// Auth packet
|
||||||
else if (header == "AUTH")
|
else if (header == "AUTH")
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed || !auth_packet_supported || f_contents.isEmpty())
|
if (!is_courtroom_constructed() || !auth_packet_supported || content.isEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool ok;
|
bool ok;
|
||||||
int authenticated = f_contents.at(0).toInt(&ok);
|
int authenticated = content.at(0).toInt(&ok);
|
||||||
if (!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);
|
w_courtroom->on_authentication_state_received(authenticated);
|
||||||
@ -762,12 +756,12 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
}
|
}
|
||||||
else if (header == "JD")
|
else if (header == "JD")
|
||||||
{
|
{
|
||||||
if (!courtroom_constructed || f_contents.isEmpty())
|
if (!is_courtroom_constructed() || content.isEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool ok;
|
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)
|
if (!ok)
|
||||||
{
|
{
|
||||||
return; // ignore malformed packet
|
return; // ignore malformed packet
|
||||||
@ -786,11 +780,11 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
// AssetURL Packet
|
// AssetURL Packet
|
||||||
else if (header == "ASS")
|
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.
|
{ // This can never be more than one link.
|
||||||
return;
|
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())
|
if (t_asset_url.isValid())
|
||||||
{
|
{
|
||||||
asset_url = t_asset_url.toString();
|
asset_url = t_asset_url.toString();
|
||||||
@ -799,7 +793,7 @@ void AOApplication::server_packet_received(AOPacket p_packet)
|
|||||||
|
|
||||||
if (log_to_demo)
|
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)
|
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);
|
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_result = read_char_ini(p_char, "showname", "Options");
|
||||||
QString f_needed = read_char_ini(p_char, "needs_showname", "Options");
|
QString f_needed = read_char_ini(p_char, "needs_showname", "Options");
|
||||||
|
|
||||||
if (p_emote != -1) {
|
if (p_emote != -1)
|
||||||
int override_idx =
|
{
|
||||||
read_char_ini(p_char, QString::number(p_emote + 1), "OptionsN").toInt();
|
int override_idx = read_char_ini(p_char, QString::number(p_emote + 1), "OptionsN").toInt();
|
||||||
if (override_idx > 0) {
|
if (override_idx > 0)
|
||||||
|
{
|
||||||
QString override_key = "Options" + QString::number(override_idx);
|
QString override_key = "Options" + QString::number(override_idx);
|
||||||
QString temp_f_result = read_char_ini(p_char, "showname", override_key);
|
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;
|
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");
|
QString f_result = read_char_ini(p_char, "blips", "Options");
|
||||||
|
|
||||||
if (p_emote != -1) {
|
if (p_emote != -1)
|
||||||
int override_idx =
|
{
|
||||||
read_char_ini(p_char, QString::number(p_emote + 1), "OptionsN").toInt();
|
int override_idx = read_char_ini(p_char, QString::number(p_emote + 1), "OptionsN").toInt();
|
||||||
if (override_idx > 0) {
|
if (override_idx > 0)
|
||||||
|
{
|
||||||
QString override_key = "Options" + QString::number(override_idx);
|
QString override_key = "Options" + QString::number(override_idx);
|
||||||
QString temp_f_result = read_char_ini(p_char, "blips", override_key);
|
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;
|
f_result = temp_f_result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f_result == "") {
|
if (f_result == "")
|
||||||
f_result =
|
{
|
||||||
read_char_ini(p_char, "gender", "Options"); // not very PC, FanatSors
|
f_result = read_char_ini(p_char, "gender", "Options"); // not very PC, FanatSors
|
||||||
if (f_result == "") f_result = "male";
|
if (f_result == "")
|
||||||
|
{
|
||||||
|
f_result = "male";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return f_result;
|
return f_result;
|
||||||
}
|
}
|
||||||
QString AOApplication::get_blips(QString p_blipname)
|
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))))
|
if (file_exists(get_sfx_suffix(get_sounds_path("../blips/" + p_blipname))))
|
||||||
|
{
|
||||||
return "../blips/" + p_blipname; // Return the cool kids variant
|
return "../blips/" + p_blipname; // Return the cool kids variant
|
||||||
|
}
|
||||||
|
|
||||||
return "sfx-blip" + p_blipname; // Return legacy variant
|
return "sfx-blip" + p_blipname; // Return legacy variant
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "gui_utils.h"
|
#include "gui_utils.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QUiLoader>
|
#include <QUiLoader>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
Loading…
Reference in New Issue
Block a user