FIXED THE MUSIC SYSTEM FINALLY AFTER THE 7TH REWRITE.

THANK YOU SO MUCH, @arieshi255 !!!

+ Made music system CONSIDERABLY more accurate, and virtually immune to server lag as we now base ticks off the game engine's real time clock in seconds, with an accuracy of up to 100ns.

+ Changed ChangeBGM function to accept a true or false, determining whether to stop the music and change it on the fly, or wait for the current song to finish.

+ Disabled debug info (getting real world time) from going into global chat.

+ Optimised music system's loop code to skip over index 0 (console) as the server console should never receive sound commands anyways.
This commit is contained in:
2025-08-19 01:58:06 -04:00
parent 06fa175eb9
commit 9fbe3b54ad
6 changed files with 78 additions and 67 deletions

View File

@@ -123,7 +123,7 @@ enum struct BOSSHANDLER {
}
case 2:{
//PrintToChatAll("Recognized 1 -> 2, things are heating up!");
AudioManager.ChangeBGM(22);
AudioManager.ChangeBGM(22, false);
FastFire2("FB.MetalFace.Train", "TeleportToPathTrack", "MFT1x0", 3.00, false);
FastFire2("FB.MetalFace.SkeleSpawner", "Enable", "", 0.0, false);
FastFire2("FB.MetalFace.SkeleSpawner", "Disable", "", 120.0, false);
@@ -137,7 +137,7 @@ enum struct BOSSHANDLER {
}
case 3:{
//PrintToChatAll("Recognized 2 -> 3, oh boi");
AudioManager.ChangeBGM(24);
AudioManager.ChangeBGM(24, false);
FastFire2("FB.MetalFace.Train", "TeleportToPathTrack", "MFT2x0", 3.00, false);
FastFire2("FB.MetalFace.MerasmusSpawner", "ForceSpawn", "", 5.0, false); //Spawn halloween bosses at MetalFace's location
FastFire2("FB.MetalFace.MonoculusSpawner", "ForceSpawn", "", 7.0, false); //Spawn halloween bosses at MetalFace's location
@@ -149,7 +149,7 @@ enum struct BOSSHANDLER {
}
case 4:{
//PrintToChatAll("Recognized 3 -> 4, OHSHITOHFUCKOHNO");
AudioManager.ChangeBGM(26);
AudioManager.ChangeBGM(26, true);
FastFire2("FB.MetalFace.Train", "TeleportToPathTrack", "MFT3x0", 3.00, false);
FastFire2("FB.MetalFace.GigaBuster", "ForceSpawn", "", 10.0, false);
}

View File

@@ -111,11 +111,11 @@ public int MenuHandlerFartsysAss(Menu menu, MenuAction action, int client, int i
public Action Command_GetCurrentSong(int client, int args) {
char buffer[16];
char tbuffer[16];
int sPos = RoundToFloor(AudioManager.ticksBGM / 66.6666666666);
int tPos = RoundToFloor(AudioManager.refireBGM / 66.6666666666);
int sPos = RoundToFloor(AudioManager.engineSecondsAdjusted() - AudioManager.timeSeconds);
int tPos = RoundToFloor(AudioManager.loopSeconds);
Format(buffer, 16, "%02d:%02d", sPos / 60, sPos % 60);
Format(tbuffer, 16, "%02d:%02d", tPos / 60, tPos % 60);
CPrintToChat(client, "The current song is: {limegreen}%s {orange}(%s / %s)", AudioManager.songName, buffer, tbuffer);
CPrintToChat(client, "The current song (%i) is: {limegreen}%s {orange}(%s / %s)", AudioManager.indexBGM, AudioManager.songName, buffer, tbuffer);
return Plugin_Handled;
}

View File

@@ -3,8 +3,8 @@
enum struct BGM {
char realPath[64];
char songName[64];
int refireTime;
int ticksOffset;
float introSeconds;
float loopSeconds;
int SNDLVL;
}
BGM BGMArray[48];
@@ -34,66 +34,77 @@ public void SQL_SNDPrefs(Database db, DBResultSet results, const char[] error, i
if (!IsValidClient(client)) return;
if (results.FetchRow()) soundPreference[client] = results.FetchInt(0);
}
//Music system rewrite for the 6th time. I will never make a change. My code will never mend. Still everything's the same and it all just fades to math.
//Music system rewrite for the 7th time. I will never make a change. My code will never mend. Still everything's the same and it all just fades to math. Stage 7, Luigi. I don't even know what that is but it's bad!
enum struct AUDIOMANAGER {
bool bgmPlaying;
bool shouldTick;
bool stopBGM;
bool tickBGMOffset;
bool hasTimeOffset;
char cachedPath[128];
char songName[128];
int indexBGM;
int refireBGM;
float timeSeconds;
float loopSeconds;
float introSeconds;
int chanBGM;
int ticksBGM;
int indexBGM;
int loops;
int VIPBGM;
void ChangeBGM(int bgm){
/** Gets the engine time, accounting for intro offset seconds **/
float engineSecondsAdjusted() {
return GetEngineTime() + this.introSeconds;
}
/** Changes the current music.
* @param bgm - The index of the music to be played
* @param instant - True = stops music NOW and changes, False = play current song then change
**/
void ChangeBGM(int bgm, bool instant) {
if (instant) {
//this.ticksBGM = -2;
this.timeSeconds = 0.0;
}
this.indexBGM = (this.VIPBGM >= 0 ? this.VIPBGM : bgm);
this.ticksBGM = -2;
this.refireBGM = 2;
this.shouldTick = true;
this.tickBGMOffset = BGMArray[this.indexBGM].ticksOffset > 0 ? true : false;
this.hasTimeOffset = BGMArray[this.indexBGM].introSeconds > 0 ? true : false;
this.stopBGM = (!StrEqual(this.cachedPath, BGMArray[this.indexBGM].realPath) ? true : false);
this.bgmPlaying = true;
if (this.indexBGM >= 20) for (int i = 0; i < MaxClients; i++) for (int s = 19; s < bgm; s++) StopSound(i, this.chanBGM, BGMArray[s].realPath); //Very quick, very dirty, very suboptimal, but gets the job done... This stops all boss music.
//if (this.indexBGM >= 20) for (int i = 0; i < MaxClients; i++) for (int s = 19; s < bgm; s++) StopSound(i, this.chanBGM, BGMArray[s].realPath); //Very quick, very dirty, very suboptimal, but gets the job done... This stops all boss music.
}
void Reset() {
this.stopBGM = true;
this.loops = 0;
this.indexBGM = GetRandomInt(1, 4);
this.ticksBGM = -2;
this.refireBGM = 2;
for (int i = 0; i < MaxClients; i++) for (int s = this.indexBGM; s < sizeof(BGMArray); s++) StopSound(i, this.chanBGM, BGMArray[s].realPath); //Very quick, very dirty, very suboptimal, but gets the job done... This stops all boss music.
this.timeSeconds = 0.0;
for (int i = 0; ++i < MaxClients;) for (int s = this.indexBGM; s < sizeof(BGMArray); s++) StopSound(i, this.chanBGM, BGMArray[s].realPath); //Very quick, very dirty, very suboptimal, but gets the job done... This stops all boss music.
AssLogger(LOGLVL_DEBUG, "AudioManager has been reset!");
}
void Stop() {
this.bgmPlaying = false;
this.loops = 0;
this.stopBGM = true;
this.ticksBGM = -2;
this.refireBGM = 2;
this.timeSeconds = 0.0;
this.shouldTick = false;
}
void TickBGM() {
this.ticksBGM++;
if (this.ticksBGM >= this.refireBGM) {
if (this.stopBGM){
for (int i = 0; i < MaxClients; ++i) {
if (this.engineSecondsAdjusted() > this.timeSeconds + this.loopSeconds) {
this.timeSeconds = GetEngineTime();
this.loops++;
for (int i = 0; ++i < MaxClients;) {
if (this.stopBGM) {
StopSound(i, this.chanBGM, this.cachedPath);
this.stopBGM = false;
this.loops = 0;
}
//if(core.gamemode > 0 && isClientInEvent(i)) continue;// To test if client is experiencing anything odd.....
CSEClient(i, BGMArray[this.indexBGM].realPath, BGMArray[this.indexBGM].SNDLVL, true, 1, 1.0, 100);
}
this.stopBGM = false;
if (GetClientCount(true) == 0) {
AssLogger(LOGLVL_INFO, "Server is empty. Music queue stopped.");
this.indexBGM = GetRandomInt(1, 4);
this.Stop();
}
strcopy(this.songName, sizeof(this.songName), BGMArray[this.indexBGM].songName);
this.refireBGM = BGMArray[this.indexBGM].refireTime;
this.ticksBGM = (this.tickBGMOffset ? BGMArray[this.indexBGM].ticksOffset : 0);
for (int i = 0; i < MaxClients; i++){
//if(core.gamemode > 0 && isClientInEvent(i)) continue;// To test if client is experiencing anything odd.....
CSEClient(i, BGMArray[this.indexBGM].realPath, BGMArray[this.indexBGM].SNDLVL, true, 1, 1.0, 100);
}
//CustomSoundEmitter(BGMArray[this.indexBGM].realPath, BGMArray[this.indexBGM].SNDLVL, true, 1, 1.0, 100);
this.introSeconds = this.loops >= 1 ? BGMArray[this.indexBGM].introSeconds : 0.0;
this.loopSeconds = BGMArray[this.indexBGM].loopSeconds;
CreateTimer(1.0, SyncMusic, this.indexBGM);
}
}

View File

@@ -629,7 +629,6 @@ void SetupCoreData(){
core.tacobell = false;
core.tickingClientHealth = false;
AudioManager.shouldTick = false;
AudioManager.tickBGMOffset = false;
WeatherManager.TornadoWarning = false;
AudioManager.cachedPath = "null";
AudioManager.songName = "null";
@@ -641,11 +640,10 @@ void SetupCoreData(){
core.curWave = 0;
core.failsafeCount = 0;
core.lastAdmin = 0;
AudioManager.refireBGM = 0;
AudioManager.loopSeconds = 0.0;
core.sacPoints = 0;
core.sacPointsMax = 60;
AudioManager.chanBGM = 6;
AudioManager.ticksBGM = 0;
AudioManager.VIPBGM = -1;
core.VIPIndex = 0;
core.waveFlags = 0;
@@ -757,6 +755,7 @@ void SetupCoreData(){
if (IsEndOfFile(confCoreData)) break;
}
AssLogger(1, "[CORE] Setting up Wave Defaults...");
PrintToServer("confCoreData returned %s", OVERRIDE_AND_GET_COREDATA());
confCoreData = OpenFile(OVERRIDE_AND_GET_COREDATA(), "rt", false);
int defIndexHW, defIndexTornado, defIndexBGM, defIndexBS, defIndexBSM, defIndexSPM; // Start at 0 because we don't have a wave 0
if(confCoreData == INVALID_HANDLE) return;
@@ -1056,29 +1055,29 @@ void RegisterAndPrecacheAllFiles(){
int sfxIndex = -1;
if(confBGM == INVALID_HANDLE) return;
if(confSFX == INVALID_HANDLE) return;
while (ReadFileLine(confBGM, bufferBGM, sizeof(bufferBGM))){
while (ReadFileLine(confBGM, bufferBGM, sizeof(bufferBGM))) {
TrimString(bufferBGM);
if (!StrContains(bufferBGM, "Path:")){
if (!StrContains(bufferBGM, "Path:")) {
bgmIndex++;
ReplaceString(bufferBGM, sizeof(bufferBGM), "Path:", "", true);
Format(BGMArray[bgmIndex].realPath, 64, bufferBGM);
}
else if (!StrContains(bufferBGM, "Title:")){
else if (!StrContains(bufferBGM, "Title:")) {
bgmNameIndex++;
ReplaceString(bufferBGM, sizeof(bufferBGM), "Title:", "", true);
Format(BGMArray[bgmNameIndex].songName, 128, bufferBGM);
}
else if (!StrContains(bufferBGM, "RefireTime:")){
else if (!StrContains(bufferBGM, "LoopSeconds:")) {
bgmRefire++;
ReplaceString(bufferBGM, sizeof(bufferBGM), "RefireTime:", "", true);
BGMArray[bgmRefire].refireTime = StringToInt(bufferBGM);
ReplaceString(bufferBGM, sizeof(bufferBGM), "LoopSeconds:", "", true);
BGMArray[bgmRefire].loopSeconds = StringToFloat(bufferBGM);
}
else if (!StrContains(bufferBGM, "OffsetTicks:")){
else if (!StrContains(bufferBGM, "IntroSeconds:")) {
bgmOffset++;
ReplaceString(bufferBGM, sizeof(bufferBGM), "OffsetTicks:", "", true);
BGMArray[bgmOffset].ticksOffset = StringToInt(bufferBGM);
ReplaceString(bufferBGM, sizeof(bufferBGM), "IntroSeconds:", "", true);
BGMArray[bgmOffset].introSeconds = StringToFloat(bufferBGM);
}
else if (!StrContains(bufferBGM, "Volume:")){
else if (!StrContains(bufferBGM, "Volume:")) {
bgmVol++;
ReplaceString(bufferBGM, sizeof(bufferBGM), "Volume:", "", true);
BGMArray[bgmVol].SNDLVL = StringToInt(bufferBGM);
@@ -1086,10 +1085,10 @@ void RegisterAndPrecacheAllFiles(){
if (IsEndOfFile(confBGM)) break;
}
PrintToServer("Precaching BGMs...");
if(confBGM != INVALID_HANDLE){
if(confBGM != INVALID_HANDLE) {
CloseHandle(confBGM);
}
while (ReadFileLine(confSFX, bufferSFX, sizeof(bufferSFX))){
while (ReadFileLine(confSFX, bufferSFX, sizeof(bufferSFX))) {
TrimString(bufferSFX);
if (!StrContains(bufferSFX, "Path:")){
sfxIndex++;
@@ -1103,7 +1102,7 @@ void RegisterAndPrecacheAllFiles(){
}
for (int i = 1; i < sizeof(BGMArray); i++){ //We start at index 1 because index 0 is used for restoring default bgm in the VIP music menu...
if(!StrEqual(BGMArray[i].realPath, "")){
AssLogger(LOGLVL_DEBUG, "Precaching BGM: %s (%s), Duration %i ticks, Start Loop Point %i ticks, Volume %i @ %i", BGMArray[i].songName, BGMArray[i].realPath, BGMArray[i].refireTime, BGMArray[i].ticksOffset, BGMArray[i].SNDLVL, i);
AssLogger(LOGLVL_DEBUG, "Precaching BGM: %s (%s), Duration %f seconds, Start Loop Point %i seconds, Volume %i @ %i", BGMArray[i].songName, BGMArray[i].realPath, BGMArray[i].loopSeconds, BGMArray[i].introSeconds, BGMArray[i].SNDLVL, i);
PrecacheSound(BGMArray[i].realPath, true);
}
}
@@ -1119,8 +1118,7 @@ void RegisterAndPrecacheAllFiles(){
//Used to keep StopSound from stopping the music we're trying to play - now with support for loop offsets!
public Action SyncMusic(Handle timer, int index) {
AudioManager.cachedPath = BGMArray[index].realPath;
AudioManager.tickBGMOffset = (BGMArray[index].ticksOffset > 0 ? true : false);
AssLogger(LOGLVL_INFO, "We are on wave %i, now playing: %s (from %s) for %i ticks. It will start looping at %i ticks.", core.curWave, AudioManager.songName, BGMArray[index].realPath, AudioManager.refireBGM, BGMArray[index].ticksOffset);
AssLogger(LOGLVL_INFO, "We are on wave %i, now playing: %s (from %s) for %f seconds. It will start looping in %f seconds.", core.curWave, AudioManager.songName, BGMArray[index].realPath, AudioManager.loopSeconds, BGMArray[index].introSeconds);
return Plugin_Stop;
}
@@ -1539,8 +1537,9 @@ public Action PerformWaveAdverts(Handle timer) {
int emnity;
char tbuffer[16];
char HintText[256];
int sPos = RoundToFloor(AudioManager.ticksBGM / 66.6666666666);
int tPos = RoundToFloor(AudioManager.refireBGM / 66.6666666666);
//int sPos = RoundToFloor((AudioManager.timeSeconds() / (GetEngineTime() + AudioManager.loopSeconds)) * AudioManager.loopSeconds);
int sPos = RoundToFloor(AudioManager.engineSecondsAdjusted() - AudioManager.timeSeconds);
int tPos = RoundToFloor(AudioManager.loopSeconds);
Format(buffer, 16, "%02d:%02d", sPos / 60, sPos % 60);
Format(tbuffer, 16, "%02d:%02d", tPos / 60, tPos % 60);
Format(HintText, sizeof(HintText), (bombState[0].isMoving ? "Payload: MOVING (%i/%i) | !sacpoints: %i/%i \n Music: %s (%s/%s)" : bombState[0].isReady ? "Payload: READY (%i/%i) | !sacpoints: %i/%i \n Music: %s (%s/%s)" : "Payload: PREPARING (%i/%i) | !sacpoints: %i/%i \n Music: %s (%s/%s)"), bombState[0].state, bombState[0].stateMax, core.sacPoints, core.sacPointsMax, AudioManager.songName, buffer, tbuffer);
@@ -1750,7 +1749,7 @@ public void OnClientPostAdminCheck(int client) {
CreateTimer(1.0, TickClientHealth);
core.tickingClientHealth = true;
}
if (!AudioManager.bgmPlaying) AudioManager.ChangeBGM(GetRandomInt(1, 4));
if (!AudioManager.bgmPlaying) AudioManager.ChangeBGM(GetRandomInt(1, 4), true);
char query[1024];
Format(query, sizeof(query), "INSERT INTO ass_activity (name, steamid, date, damagedealtsession, killssession, deathssession, bombsresetsession, sacrificessession) VALUES ('%N', %d, CURRENT_DATE, 0, 0, 0, 0, 0) ON DUPLICATE KEY UPDATE name = '%N', date = CURRENT_DATE, damagedealtsession = 0, killssession = 0, deathssession = 0, bombsresetsession = 0, sacrificessession = 0;", client, steamID, client);
Ass_Database.Query(Database_FastQuery, query);

View File

@@ -30,7 +30,7 @@ public Action StatsTracker(Handle timer) {
FastFire2("FBMetric.TimeHH", "SetTextureIndex", hour, 0.0, false);
FastFire2("FBMetric.TimeMM", "SetTextureIndex", minute, 0.0, false);
FastFire2("FBMetric.TimeAMPM", "SetTextureIndex", ampm, 0.0, false);
PrintToChatAll("Current time is %s:%s %s", hour, minute, StringToInt(ampm) == 0 ? "AM" : "PM");
//PrintToChatAll("Current time is %s:%s %s", hour, minute, StringToInt(ampm) == 0 ? "AM" : "PM");
CreateTimer(15.0, StatsTracker);
if (!Get_Ass_Database()) return Plugin_Stop;
char query[512];

View File

@@ -1,4 +1,4 @@
public char PLUGIN_VERSION[8] = "8.2.0c";
public char PLUGIN_VERSION[8] = "8.3.0a";
void sudo(int task) {
AssLogger(LOGLVL_DEBUG, "Calling sudo with %i", task);
switch (task) {
@@ -22,7 +22,7 @@ void sudo(int task) {
PerformWaveSetup();
float hwn = GetRandomFloat(core.HWNMin, core.HWNMax);
CreateTimer(hwn, HWBosses);
AudioManager.ChangeBGM(core.tacobell ? tacoBellBGMIndex[core.curWave] : DefaultsArray[core.curWave].defBGMIndex);
AudioManager.ChangeBGM(core.tacobell ? tacoBellBGMIndex[core.curWave] : DefaultsArray[core.curWave].defBGMIndex, true);
PrintToChatAll("WARNING, AUDIOMANAGER'S CHANGEBGM FUNCTION IS DEPRECATED IN FAVOR OF THE NEW CONFIGS. FIX THIS IMMEDIATELY.");
return;
}
@@ -634,19 +634,19 @@ void sudo(int task) {
}
case 421:{
FastFire2("weather.sky", "Skin", "2", 0.0, false);
AudioManager.ChangeBGM(28);
AudioManager.ChangeBGM(28, false);
WeatherManager.fogColorRTarget = 95.0;
WeatherManager.fogColorGTarget = 35.0;
WeatherManager.fogColorBTarget = 35.0;
}
case 422:{
AudioManager.ChangeBGM(29);
AudioManager.ChangeBGM(29, false);
}
case 423:{
AudioManager.ChangeBGM(30);
AudioManager.ChangeBGM(30, false);
}
case 424:{
AudioManager.ChangeBGM(31);
AudioManager.ChangeBGM(31, false);
}
case 425:{
for (int i = 0; i < 32; i++) {
@@ -686,9 +686,10 @@ void sudo(int task) {
AudioManager.indexBGM = 11;
AudioManager.stopBGM = true;
}
// FINAL Music system rewrite (again) AGAINNNNNNNNNNNN.... and again!
// FINAL Music system rewrite (again) AGAINNNNNNNNNNNN.... and again!... and again :p
case 1000: {
AudioManager.ChangeBGM(AudioManager.indexBGM);
AudioManager.shouldTick = true;
AudioManager.ChangeBGM(AudioManager.indexBGM, true);
}
//Stop current song
case 1001: {
@@ -978,8 +979,8 @@ public Action TimedOperator(Handle timer, int job) {
//DO THE THING ALREADY
case 7: {
core.sephiroth = true;
AudioManager.ticksBGM = 0;
AudioManager.refireBGM = BGMArray[16].refireTime;
//AudioManager.ticksBGM = 0;
AudioManager.loopSeconds = BGMArray[16].loopSeconds;
}
//Signal boss to actually spawn after delay.
case 8: {