|
@@ -12,7 +12,7 @@
|
|
|
#pragma newdecls required
|
|
|
#include <round_end_music>
|
|
|
|
|
|
-#define PLUGIN_VERSION "0.0.0"
|
|
|
+#define PLUGIN_VERSION "0.1.0"
|
|
|
public Plugin myinfo = {
|
|
|
name = "[CSRD] Round End Music",
|
|
|
author = "nosoop",
|
|
@@ -24,9 +24,12 @@ public Plugin myinfo = {
|
|
|
bool g_bQueueLocked = false;
|
|
|
ArrayList g_QueuedSongs, g_ActiveSongs, g_PlayedSongs;
|
|
|
|
|
|
+ConVar g_ConVarMaxActiveSongs, g_ConVarEnabled;
|
|
|
+
|
|
|
Handle g_RequestSongForward;
|
|
|
|
|
|
int g_nMaxActiveSongs = 5;
|
|
|
+bool g_bRoundEndMusicActive;
|
|
|
|
|
|
public void OnPluginStart() {
|
|
|
g_QueuedSongs = new ArrayList();
|
|
@@ -39,6 +42,14 @@ public void OnPluginStart() {
|
|
|
|
|
|
RegAdminCmd("sm_playsong", AdminCmd_PlaySong, ADMFLAG_ROOT);
|
|
|
RegAdminCmd("sm_peekqueue", AdminCmd_PeekQueue, ADMFLAG_ROOT);
|
|
|
+
|
|
|
+ g_ConVarMaxActiveSongs = CreateConVar("sm_rem_active_songs", "5",
|
|
|
+ "Maximum number of songs available for playback on a single map.", _,
|
|
|
+ true, 1.0, false);
|
|
|
+ g_ConVarEnabled = CreateConVar("sm_rem_enabled", "1", "Enables Round End Music.", _,
|
|
|
+ true, 0.0, true, 1.0);
|
|
|
+
|
|
|
+ AutoExecConfig();
|
|
|
}
|
|
|
|
|
|
public Action AdminCmd_PlaySong(int client, int argc) {
|
|
@@ -70,14 +81,22 @@ void PrintSongList(int client, const char[] listName, ArrayList songList) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-public void OnAutoConfigsBuffered() {
|
|
|
+public void OnConfigsExecuted() {
|
|
|
// TODO pull g_nMaxActiveSongs from ConVar -- it can't change during map
|
|
|
+ g_nMaxActiveSongs = g_ConVarMaxActiveSongs.IntValue;
|
|
|
+ g_bRoundEndMusicActive = g_ConVarEnabled.BoolValue;
|
|
|
|
|
|
g_bQueueLocked = false;
|
|
|
Call_StartForward(g_RequestSongForward);
|
|
|
Call_Finish();
|
|
|
g_bQueueLocked = true;
|
|
|
|
|
|
+ /**
|
|
|
+ * It's okay if there are songs in the active list, as it won't be processed if the plugin
|
|
|
+ * is set as disabled. However...
|
|
|
+ *
|
|
|
+ * TODO make the active song count implicitly zero when disabled?
|
|
|
+ */
|
|
|
if (g_nMaxActiveSongs < g_ActiveSongs.Length) {
|
|
|
// Put excess songs back in the head of the queue
|
|
|
// Used if fewer active songs are required for long maps
|
|
@@ -86,10 +105,16 @@ public void OnAutoConfigsBuffered() {
|
|
|
int pos = g_ActiveSongs.Length - 1;
|
|
|
MusicEntry song = g_ActiveSongs.Get(pos);
|
|
|
|
|
|
- g_QueuedSongs.ShiftUp(0);
|
|
|
+ // Insert songs at the top of the queued songs list.
|
|
|
+ if (g_QueuedSongs.Length == 0) {
|
|
|
+ // Fix attempting to shift contents of an empty queue up.
|
|
|
+ g_QueuedSongs.Resize(1);
|
|
|
+ } else {
|
|
|
+ g_QueuedSongs.ShiftUp(0);
|
|
|
+ }
|
|
|
g_QueuedSongs.Set(0, song);
|
|
|
|
|
|
- g_ActiveSongs.Erase(0);
|
|
|
+ g_ActiveSongs.Erase(pos);
|
|
|
}
|
|
|
} else {
|
|
|
// Take up to g_nMaxActiveSongs songs from queue and move them to g_ActiveSongs
|
|
@@ -101,29 +126,38 @@ public void OnAutoConfigsBuffered() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Do the Fisher-Yates.
|
|
|
- // http://spin.atomicobject.com/2014/08/11/fisher-yates-shuffle-randomization-algorithm/
|
|
|
- int nActiveSongs = g_ActiveSongs.Length < g_nMaxActiveSongs?
|
|
|
- g_ActiveSongs.Length : g_nMaxActiveSongs;
|
|
|
-
|
|
|
- for (int i = 0; i < nActiveSongs; i+= 1) {
|
|
|
- int s = GetRandomInt(i, nActiveSongs - 1);
|
|
|
- SwapArrayItems(g_ActiveSongs, i, s);
|
|
|
-
|
|
|
- MusicEntry song = g_ActiveSongs.Get(i);
|
|
|
-
|
|
|
- char title[64], source[64], filePath[PLATFORM_MAX_PATH];
|
|
|
- song.GetTitle(title, sizeof(title));
|
|
|
- song.GetSource(source, sizeof(source));
|
|
|
- song.GetFilePath(filePath, sizeof(filePath));
|
|
|
-
|
|
|
- char fileDownloadPath[PLATFORM_MAX_PATH];
|
|
|
- Format(fileDownloadPath, sizeof(fileDownloadPath), "sound/%s", filePath);
|
|
|
- AddFileToDownloadsTable(fileDownloadPath);
|
|
|
-
|
|
|
- PrecacheSound(filePath);
|
|
|
+ /**
|
|
|
+ * Check to see if we should play music on this map. If not, then don't process the active
|
|
|
+ * music list.
|
|
|
+ */
|
|
|
+ if (g_bRoundEndMusicActive) {
|
|
|
+ // Do the Fisher-Yates.
|
|
|
+ // http://spin.atomicobject.com/2014/08/11/fisher-yates-shuffle-randomization-algorithm/
|
|
|
+ int nActiveSongs = g_ActiveSongs.Length < g_nMaxActiveSongs?
|
|
|
+ g_ActiveSongs.Length : g_nMaxActiveSongs;
|
|
|
|
|
|
- PrintToServer("[rem] Added song %d: %s", i + 1, filePath);
|
|
|
+ for (int i = 0; i < nActiveSongs; i+= 1) {
|
|
|
+ int s = GetRandomInt(i, nActiveSongs - 1);
|
|
|
+ SwapArrayItems(g_ActiveSongs, i, s);
|
|
|
+
|
|
|
+ MusicEntry song = g_ActiveSongs.Get(i);
|
|
|
+
|
|
|
+ char title[64], source[64], filePath[PLATFORM_MAX_PATH];
|
|
|
+ song.GetTitle(title, sizeof(title));
|
|
|
+ song.GetSource(source, sizeof(source));
|
|
|
+ song.GetFilePath(filePath, sizeof(filePath));
|
|
|
+
|
|
|
+ char fileDownloadPath[PLATFORM_MAX_PATH];
|
|
|
+ Format(fileDownloadPath, sizeof(fileDownloadPath), "sound/%s", filePath);
|
|
|
+ AddFileToDownloadsTable(fileDownloadPath);
|
|
|
+
|
|
|
+ PrecacheSound(filePath);
|
|
|
+
|
|
|
+ PrintToServer("[rem] Added song %d: %s", i + 1, filePath);
|
|
|
+ }
|
|
|
+ PrintToServer("[rem] Round End Music plugin enabled.");
|
|
|
+ } else {
|
|
|
+ PrintToServer("[rem] Round End Music plugin disabled.");
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -148,7 +182,7 @@ public void OnMapEnd() {
|
|
|
* Play pending endround music.
|
|
|
*/
|
|
|
void PlayRoundEndMusic() {
|
|
|
- if (g_ActiveSongs.Length == 0) {
|
|
|
+ if (g_ActiveSongs.Length == 0 || !g_bRoundEndMusicActive) {
|
|
|
PrintToServer("no songs to play :(");
|
|
|
return;
|
|
|
}
|
|
@@ -157,17 +191,7 @@ void PlayRoundEndMusic() {
|
|
|
|
|
|
// mock play for testing
|
|
|
// TODO move into a function with shiny forwards
|
|
|
- char filePath[PLATFORM_MAX_PATH];
|
|
|
- song.GetFilePath(filePath, sizeof(filePath));
|
|
|
-
|
|
|
- PrintToServer("mock play song %s", filePath);
|
|
|
- EmitSoundToAll(filePath);
|
|
|
-
|
|
|
- if (g_PlayedSongs.FindValue(song) == -1) {
|
|
|
- g_PlayedSongs.Push(song);
|
|
|
- }
|
|
|
-
|
|
|
- g_ActiveSongs.Erase(0);
|
|
|
+ EmitRoundEndMusic(song);
|
|
|
|
|
|
// if 'active' is empty, copy all back into 'active' without removing from 'played'
|
|
|
if (g_ActiveSongs.Length == 0) {
|
|
@@ -184,12 +208,33 @@ void PlayRoundEndMusic() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void EmitRoundEndMusic(MusicEntry song) {
|
|
|
+ char filePath[PLATFORM_MAX_PATH];
|
|
|
+ song.GetFilePath(filePath, sizeof(filePath));
|
|
|
+
|
|
|
+ PrintToServer("mock play song %s", filePath);
|
|
|
+ EmitSoundToAll(filePath);
|
|
|
+
|
|
|
+ // TODO create new forward OnRoundEndMusicPlayed(MusicEntry song) ?
|
|
|
+ // - Plugin_Continue uses default handling
|
|
|
+ // - Plugin_Handled does not
|
|
|
+ // - Plugin_Stop doesn't either, but the implication is that the entire endround is canceled
|
|
|
+ // (i.e., it shouldn't move it to the played list)
|
|
|
+
|
|
|
+ if (g_PlayedSongs.FindValue(song) == -1) {
|
|
|
+ g_PlayedSongs.Push(song);
|
|
|
+ }
|
|
|
+
|
|
|
+ g_ActiveSongs.Erase(0);
|
|
|
+}
|
|
|
+
|
|
|
public void OnRoundEnd(Event event, const char[] name, bool dontBroadcast) {
|
|
|
PlayRoundEndMusic();
|
|
|
}
|
|
|
|
|
|
// menu: read entries from g_PlayedSongs and then g_ActiveSongs if not empty
|
|
|
// that *should* maintain initial play order
|
|
|
+// maybe we should just provide a function that provides the entire list and active counts?
|
|
|
|
|
|
/* Native function calls */
|
|
|
public APLRes AskPluginLoad2(Handle self, bool late, char[] error, int err_max) {
|