From f9dcaa2aa51b4e1fe149924ba806ec94adaf28c9 Mon Sep 17 00:00:00 2001 From: Salanto <62221668+Salanto@users.noreply.github.com> Date: Sun, 12 Sep 2021 22:32:10 +0200 Subject: [PATCH] Implement a basic and functional jukebox implementation --- core/include/aoclient.h | 8 ++++++ core/include/area_data.h | 56 +++++++++++++++++++++++++++++++++++++ core/src/area_data.cpp | 49 ++++++++++++++++++++++++++++++++ core/src/commands/music.cpp | 17 ++++++++++- core/src/config_manager.cpp | 4 ++- core/src/packets.cpp | 9 ++++++ core/src/server.cpp | 5 +++- 7 files changed, 145 insertions(+), 3 deletions(-) diff --git a/core/include/aoclient.h b/core/include/aoclient.h index baacc4a..da735eb 100644 --- a/core/include/aoclient.h +++ b/core/include/aoclient.h @@ -1809,6 +1809,13 @@ class AOClient : public QObject { */ void cmdToggleMusic(int argc, QStringList argv); + /** + * @brief cmdToggleJukebox Toggles jukebox status in the current area. + * + * @details No arguments. + */ + void cmdToggleJukebox(int argc, QStringList argv); + ///@} /** @@ -2121,6 +2128,7 @@ class AOClient : public QObject { {"ignore_bglist", {ACLFlags.value("IGNORE_BGLIST"),0, &AOClient::cmdIgnoreBgList}}, {"notice", {ACLFlags.value("SEND_NOTICE"), 1, &AOClient::cmdNotice}}, {"noticeg", {ACLFlags.value("SEND_NOTICE"), 1, &AOClient::cmdNoticeGlobal}}, + {"togglejukebox", {ACLFlags.value("None"), 0, &AOClient::cmdToggleJukebox}}, }; /** diff --git a/core/include/area_data.h b/core/include/area_data.h index 2bdad36..a5bddac 100644 --- a/core/include/area_data.h +++ b/core/include/area_data.h @@ -27,6 +27,7 @@ #include #include #include +#include class Logger; @@ -295,6 +296,15 @@ class AreaData : public QObject { */ LockStatus lockStatus() const; + /** + * @brief Returns the jukebox status of the area. + * + * @return See short description. + * + * @see #m_jukebox + */ + bool isjukeboxEnabled() const; + /** * @brief Locks the area, setting it to LOCKED. */ @@ -778,6 +788,30 @@ class AreaData : public QObject { */ void toggleIgnoreBgList(); + /** + * @brief Toggles wether the jukebox is enabled or not. + */ + void toggleJukebox(); + + /** + * @brief Adds a song to the Jukeboxs queue. + */ + bool addJukeboxSong(QString f_song); + + public slots: + + /** + * @brief Plays a random song from the jukebox. Plays the same if only one is left. + */ + void switchJukeboxSong(); + + signals: + + /** + * @brief Changes the song in the current area when the jukebox timer expires. + */ + void playJukeboxSong(AOPacket f_packet, int f_area_index); + private: /** * @brief The list of timers available in the area. @@ -966,6 +1000,28 @@ private: * @brief Whether or not to ignore the server defined background list. If true, any background can be set in an area. */ bool m_ignoreBgList; + + // Jukebox specific members + /** + * @brief Stores the songs added to the jukebox to be played. + * + * @details This contains the names of each song, noteworthy is that none of the songs are able to be entered twice. + * + */ + QVector m_jukebox_queue; + + /** + * @brief Triggers the playing of the next song once the last song has fully played. + * + * @details While this may be considered bad design, I do not care. + * It triggers a direct broadcast of the MC packet in the area. + */ + QTimer* m_jukebox_timer; + + /** + * @brief Wether or not the jukebox is enabled in this area. + */ + bool m_jukebox; }; #endif // AREA_DATA_H diff --git a/core/src/area_data.cpp b/core/src/area_data.cpp index 7f5eddc..2e0df34 100644 --- a/core/src/area_data.cpp +++ b/core/src/area_data.cpp @@ -48,6 +48,7 @@ AreaData::AreaData(QString p_name, int p_index) : m_toggleMusic = areas_ini->value("toggle_music", "true").toBool(); m_shownameAllowed = areas_ini->value("shownames_allowed", "true").toBool(); m_ignoreBgList = areas_ini->value("ignore_bglist", "false").toBool(); + m_jukebox = areas_ini->value("jukebox_enabled", "false").toBool(); areas_ini->endGroup(); QTimer* timer1 = new QTimer(); m_timers.append(timer1); @@ -57,6 +58,9 @@ AreaData::AreaData(QString p_name, int p_index) : m_timers.append(timer3); QTimer* timer4 = new QTimer(); m_timers.append(timer4); + m_jukebox_timer = new QTimer(); + connect(m_jukebox_timer, &QTimer::timeout, + this, &AreaData::switchJukeboxSong); } const QMap AreaData::map_statuses = { @@ -131,6 +135,11 @@ AreaData::LockStatus AreaData::lockStatus() const return m_locked; } +bool AreaData::isjukeboxEnabled() const +{ + return m_jukebox; +} + void AreaData::lock() { m_locked = LockStatus::LOCKED; @@ -504,3 +513,43 @@ void AreaData::toggleIgnoreBgList() { m_ignoreBgList = !m_ignoreBgList; } + +void AreaData::toggleJukebox() +{ + m_jukebox = !m_jukebox; +} + +bool AreaData::addJukeboxSong(QString f_song) +{ + if(!m_jukebox_queue.contains(f_song)) { + if (m_jukebox_queue.size() == 0) { + emit playJukeboxSong(AOPacket("MC",{f_song,QString::number(-1)}), index()); + m_jukebox_timer->start(ConfigManager::songInformation(f_song) * 1000); + } + m_jukebox_queue.append(f_song); + return true; + } + else { + return false; + } +} + +void AreaData::switchJukeboxSong() +{ + QString l_song_name; + if(m_jukebox_queue.size() == 1) { + l_song_name = m_jukebox_queue[0]; + emit playJukeboxSong(AOPacket("MC",{l_song_name,QString::number(-1)}), m_index); + m_jukebox_timer->start(ConfigManager::songInformation(l_song_name) * 1000); + } + else { + int l_random_index = QRandomGenerator::system()->bounded(m_jukebox_queue.size() -1); + l_song_name = m_jukebox_queue[l_random_index]; + emit playJukeboxSong(AOPacket("MC",{l_song_name,QString::number(-1)}), m_index); + m_jukebox_timer->start(ConfigManager::songInformation(m_jukebox_queue[l_random_index]) * 1000); + m_jukebox_queue.remove(l_random_index); + m_jukebox_queue.squeeze(); + } + currentMusic() = l_song_name; + musicPlayerBy() = "Jukebox"; +} diff --git a/core/src/commands/music.cpp b/core/src/commands/music.cpp index 35fec63..5a5b58e 100644 --- a/core/src/commands/music.cpp +++ b/core/src/commands/music.cpp @@ -16,7 +16,6 @@ // along with this program. If not, see . // ////////////////////////////////////////////////////////////////////////////////////// #include "include/aoclient.h" - // This file is for commands under the music category in aoclient.h // Be sure to register the command in the header before adding it here! @@ -112,3 +111,19 @@ void AOClient::cmdToggleMusic(int argc, QStringList argv) QString l_state = l_area->isMusicAllowed() ? "allowed." : "disallowed."; sendServerMessage("Music in this area is now " + l_state); } + +void AOClient::cmdToggleJukebox(int argc, QStringList argv) +{ + Q_UNUSED(argc); + Q_UNUSED(argv); + + if (checkAuth(ACLFlags.value("CM")) | m_authenticated) { + AreaData* l_area = server->m_areas.value(m_current_area); + l_area->toggleJukebox(); + QString l_state = l_area->isjukeboxEnabled() ? "enabled." : "disabled."; + sendServerMessageArea("The jukebox in this area has been " + l_state); + } + else { + sendServerMessage("You do not have permission to change the jukebox status."); + } +} diff --git a/core/src/config_manager.cpp b/core/src/config_manager.cpp index c8f1680..fbfadf8 100644 --- a/core/src/config_manager.cpp +++ b/core/src/config_manager.cpp @@ -142,6 +142,7 @@ QStringList ConfigManager::musiclist() QJsonArray l_Json_root_array = l_music_list_json.array(); QJsonObject l_child_obj; QJsonArray l_child_array; + QStringList l_musiclist; for (int i = 0; i <= l_Json_root_array.size() -1; i++){ //Iterate trough entire JSON file to assemble musiclist l_child_obj = l_Json_root_array.at(i).toObject(); @@ -149,6 +150,7 @@ QStringList ConfigManager::musiclist() QString l_category_name = l_child_obj["category"].toString(); if (!l_category_name.isEmpty()) { m_musicList->insert(l_category_name,0); + l_musiclist.append(l_category_name); } else { qWarning() << "Category name not set. This may cause the musiclist to be displayed incorrectly."; @@ -160,11 +162,11 @@ QStringList ConfigManager::musiclist() QString l_song_name = l_song_obj["name"].toString(); int l_song_duration = l_song_obj["length"].toVariant().toFloat(); m_musicList->insert(l_song_name,l_song_duration); + l_musiclist.append(l_song_name); } } l_music_json.close(); - QStringList l_musiclist = m_musicList->keys(); if(!l_musiclist[0].contains("==")) // Add a default category if none exists l_musiclist.insert(0,"==Music=="); diff --git a/core/src/packets.cpp b/core/src/packets.cpp index 5360f4f..846a073 100644 --- a/core/src/packets.cpp +++ b/core/src/packets.cpp @@ -319,6 +319,15 @@ void AOClient::pktChangeMusic(AreaData* area, int argc, QStringList argv, AOPack l_final_song = "~stop.mp3"; else l_final_song = l_argument; + + if (area->isjukeboxEnabled()) { + if (area->addJukeboxSong(l_final_song)) + sendServerMessage("Your song has been added to the Jukebox queue."); + else + sendServerMessage("Your song could not be added to the jukebox queue. It already exists"); + return; + } + AOPacket l_music_change("MC", {l_final_song, argv[1], m_showname, "1", "0", l_effects}); area->currentMusic() = l_final_song; area->musicPlayerBy() = m_showname; diff --git a/core/src/server.cpp b/core/src/server.cpp index e9f0ab4..8ff9212 100644 --- a/core/src/server.cpp +++ b/core/src/server.cpp @@ -91,7 +91,10 @@ void Server::start() QStringList raw_area_names = ConfigManager::rawAreaNames(); for (int i = 0; i < raw_area_names.length(); i++) { QString area_name = raw_area_names[i]; - m_areas.insert(i, new AreaData(area_name, i)); + AreaData* l_area = new AreaData(area_name, i); + m_areas.insert(i, l_area); + connect(l_area, &AreaData::playJukeboxSong, + this, QOverload::of(&Server::broadcast)); } //Rate-Limiter for IC-Chat