# HG changeset patch # User Adam Kaminski # Date 1604810536 18000 # Sat Nov 07 23:42:16 2020 -0500 # Node ID a7015886133535a45f36d2920862bfdd6c320bb0 # Parent df4ba3bf564ebde4ec875b64b9c5e7de0e255023 Fixed looping actor sounds not being synced to newly connected clients, also prevented the server from creating redundant net traffic by telling clients to replay the same looping sounds on the actor's channels. diff -r df4ba3bf564e -r a70158861335 docs/zandronum-history.txt --- a/docs/zandronum-history.txt Wed Nov 04 11:58:06 2020 -0500 +++ b/docs/zandronum-history.txt Sat Nov 07 23:42:16 2020 -0500 @@ -43,6 +43,7 @@ - - Fixed the obituary for the BFG tracer not being used if a player was killed by them. [Kaminsky] - - Fixed desaturated translations created with CreateTranslation() not syncing with clients in an online game. [Kaminsky] - - Fixed serverside and clientside ACS HudMessages using different id namespaces so that they couldn't replace each other. [Kaminsky] +- - Fixed looping actor sounds not being synced to newly connected clients, also prevented the server from creating redundant net traffic by telling clients to replay the same looping sounds on the actor's channels. [Kaminsky] ! - sv_forcegldefaults renamed to sv_forcevideodefaults. The old name still exists for compatibility. [Dusk] ! - r_3dfloors is now forced to be true when sv_forcevideodefaults is true. [Dusk] ! - When the wad authentication fails for a connecting client, the client only reports the missing and incompatible PWADS instead of all of them. [Pol Marcet] diff -r df4ba3bf564e -r a70158861335 src/p_acs.cpp --- a/src/p_acs.cpp Wed Nov 04 11:58:06 2020 -0500 +++ b/src/p_acs.cpp Sat Nov 07 23:42:16 2020 -0500 @@ -6075,11 +6075,43 @@ { if (!looping) { - S_Sound(spot, chan, sid, vol, atten, true); // [EP] Inform the clients. + // [AK] Don't start the sound if we're the server and this actor is already looping the sound on the same channel. + if ( NETWORK_GetState() != NETSTATE_SERVER || (( chan & CHAN_LOOP ) && SERVER_IsChannelLoopingSound( spot, chan & 7, sid )) == false ) + { + S_Sound(spot, chan, sid, vol, atten, true); // [EP] Inform the clients. + + // [AK] If we're the server, we may need to add or replace the actor's channel to the list of looping sound channels. + if ( NETWORK_GetState() == NETSTATE_SERVER ) + { + if ( chan & CHAN_LOOP ) + { + if ( SERVER_IsChannelLooping( spot, chan & 7 ) ) + SERVER_ReplaceLoopingChannel( spot, chan, sid, vol, atten ); + else + SERVER_AddLoopingChannel( spot, chan, sid, vol, atten ); + } + // [AK] If the sound isn't looping, remove the actor's channel from the list of looping sound channels. + else + SERVER_RemoveLoopingChannel( spot, chan & 7 ); + } + } } else if (!S_IsActorPlayingSomething(spot, chan & 7, sid)) { - S_Sound(spot, chan | CHAN_LOOP, sid, vol, atten, true); // [EP] Inform the clients. + // [AK] Don't start the sound if we're the server and this actor is already looping the sound on the same channel. + if ( NETWORK_GetState() != NETSTATE_SERVER || SERVER_IsChannelLoopingSound( spot, chan & 7, sid ) == false ) + { + S_Sound(spot, chan | CHAN_LOOP, sid, vol, atten, true); // [EP] Inform the clients. + + // [AK] Add or replace the actor's channel to the list of looping sound channels. + if ( NETWORK_GetState() == NETSTATE_SERVER ) + { + if ( SERVER_IsChannelLooping( spot, chan & 7 ) ) + SERVER_ReplaceLoopingChannel( spot, chan, sid, vol, atten ); + else + SERVER_AddLoopingChannel( spot, chan, sid, vol, atten ); + } + } } } } @@ -6094,6 +6126,10 @@ if (args[0] == 0) { S_StopSound(activator, chan); + + // [AK] If we're the server, remove the activator's channel from the list of looping channels. + if ( NETWORK_GetState() == NETSTATE_SERVER ) + SERVER_RemoveLoopingChannel( activator, chan ); } else { @@ -6103,6 +6139,10 @@ while ((spot = it.Next()) != NULL) { S_StopSound(spot, chan); + + // [AK] If we're the server, remove the actor's channel from the list of looping channels. + if ( NETWORK_GetState() == NETSTATE_SERVER ) + SERVER_RemoveLoopingChannel( spot, chan ); } } } diff -r df4ba3bf564e -r a70158861335 src/p_mobj.cpp --- a/src/p_mobj.cpp Wed Nov 04 11:58:06 2020 -0500 +++ b/src/p_mobj.cpp Sat Nov 07 23:42:16 2020 -0500 @@ -5286,6 +5286,10 @@ // Transform any playing sound into positioned, non-actor sounds. S_RelinkSound (this, NULL); + // [AK] If we're the server, clear all looping channels belonging to this actor. + if ( NETWORK_GetState() == NETSTATE_SERVER ) + SERVER_ClearLoopingChannels( this ); + Super::Destroy (); } diff -r df4ba3bf564e -r a70158861335 src/p_setup.cpp --- a/src/p_setup.cpp Wed Nov 04 11:58:06 2020 -0500 +++ b/src/p_setup.cpp Sat Nov 07 23:42:16 2020 -0500 @@ -3967,6 +3967,8 @@ SERVER_ClearEditedTranslations( ); // [BB] And the stored sector links. SERVER_ClearSectorLinks( ); + // [AK] And the looping sound channels of any actors. + SERVER_ClearLoopingChannels( NULL ); } // Initial height of PointOfView will be set by player think. diff -r df4ba3bf564e -r a70158861335 src/sv_main.cpp --- a/src/sv_main.cpp Wed Nov 04 11:58:06 2020 -0500 +++ b/src/sv_main.cpp Sat Nov 07 23:42:16 2020 -0500 @@ -243,6 +243,9 @@ // [BB] List of all sector links created by calls to Sector_SetLink. static TArray g_SectorLinkList; +// [AK] List of all actor sound channels containing looping sounds. +static TArray g_LoopingChannelList; + // [BB] Seperate log file to debug the tic buffer. static FILE *MoveCMDRegulatorLogFile = NULL; @@ -2649,6 +2652,10 @@ } } + // [AK] Send out any looping sounds that might be playing on an actor's sound channels. + for ( ulIdx = 0; ulIdx < g_LoopingChannelList.Size(); ulIdx++ ) + SERVERCOMMANDS_SoundActor( g_LoopingChannelList[ulIdx].Actor, g_LoopingChannelList[ulIdx].EntChannel | g_LoopingChannelList[ulIdx].ChanFlags | CHAN_LOOP, S_GetName( g_LoopingChannelList[ulIdx].SoundID ), g_LoopingChannelList[ulIdx].Volume, g_LoopingChannelList[ulIdx].DistanceScale, MAXPLAYERS, 0, true ); + // [BB] If the sky differs from the standard sky, let the client know about it. if ( level.info && ( ( stricmp( level.skypic1, level.info->skypic1 ) != 0 ) @@ -4013,6 +4020,122 @@ //***************************************************************************** // +void SERVER_AddLoopingChannel( AActor *pActor, int channel, FSoundID soundid, float fVolume, float fAttenuation ) +{ + if ( pActor == NULL ) + return; + + FSoundChan chan; + + chan.Actor = pActor; + chan.EntChannel = channel & 7; + chan.ChanFlags = channel & ~7; + chan.SoundID = soundid; + chan.Volume = fVolume; + chan.DistanceScale = fAttenuation; + + g_LoopingChannelList.Push( chan ); +} + +//***************************************************************************** +// +void SERVER_ReplaceLoopingChannel( AActor *pActor, int channel, FSoundID soundid, float fVolume, float fAttenuation ) +{ + if ( pActor == NULL ) + return; + + for ( unsigned int i = 0; i < g_LoopingChannelList.Size(); i++ ) + { + if ( g_LoopingChannelList[i].Actor == pActor && g_LoopingChannelList[i].EntChannel == ( channel & 7 )) + { + g_LoopingChannelList[i].ChanFlags = channel & ~7; + g_LoopingChannelList[i].SoundID = soundid; + g_LoopingChannelList[i].Volume = fVolume; + g_LoopingChannelList[i].DistanceScale = fAttenuation; + break; + } + } +} + +//***************************************************************************** +// +void SERVER_RemoveLoopingChannel( AActor *pActor, int channel ) +{ + if ( pActor == NULL ) + return; + + for ( unsigned int i = 0; i < g_LoopingChannelList.Size(); i++ ) + { + if ( g_LoopingChannelList[i].Actor == pActor && g_LoopingChannelList[i].EntChannel == channel ) + { + g_LoopingChannelList.Delete( i ); + break; + } + } +} + +//***************************************************************************** +// +bool SERVER_IsChannelLooping( AActor *pActor, int channel ) +{ + if ( pActor == NULL ) + return false; + + for ( unsigned int i = 0; i < g_LoopingChannelList.Size(); i++ ) + { + if ( g_LoopingChannelList[i].Actor == pActor && g_LoopingChannelList[i].EntChannel == channel ) + return true; + } + + return false; +} + +//***************************************************************************** +// +bool SERVER_IsChannelLoopingSound( AActor *pActor, int channel, int soundid ) +{ + if ( pActor == NULL ) + return false; + + for ( unsigned int i = 0; i < g_LoopingChannelList.Size(); i++ ) + { + if ( g_LoopingChannelList[i].Actor == pActor && g_LoopingChannelList[i].EntChannel == channel ) + { + if ( g_LoopingChannelList[i].SoundID == soundid ) + { + return true; + } + } + } + + return false; +} + +//***************************************************************************** +// +void SERVER_ClearLoopingChannels( AActor *pActor ) +{ + unsigned int i = 0; + + if ( pActor != NULL ) + { + while ( i < g_LoopingChannelList.Size() ) + { + if ( g_LoopingChannelList[i].Actor == pActor ) + { + g_LoopingChannelList.Delete( i ); + continue; + } + + i++; + } + } + else + g_LoopingChannelList.Clear( ); +} + +//***************************************************************************** +// void SERVER_ErrorCleanup( void ) { ULONG ulIdx; diff -r df4ba3bf564e -r a70158861335 src/sv_main.h --- a/src/sv_main.h Wed Nov 04 11:58:06 2020 -0500 +++ b/src/sv_main.h Sat Nov 07 23:42:16 2020 -0500 @@ -505,6 +505,12 @@ void SERVER_ClearEditedTranslations( void ); void SERVER_AddSectorLink( ULONG ulSector, int iArg1, int iArg2, int iArg3 ); void SERVER_ClearSectorLinks( void ); +void SERVER_AddLoopingChannel( AActor *pActor, int channel, FSoundID soundid, float fVolume, float fAttenuation ); +void SERVER_ReplaceLoopingChannel( AActor *pActor, int channel, FSoundID soundid, float fVolume, float fAttenuation ); +void SERVER_RemoveLoopingChannel( AActor *pActor, int channel ); +bool SERVER_IsChannelLooping( AActor *pActor, int channel ); +bool SERVER_IsChannelLoopingSound( AActor *pActor, int channel, int soundid ); +void SERVER_ClearLoopingChannels( AActor *pActor ); void SERVER_ErrorCleanup( void ); void SERVER_ParsePacket( BYTESTREAM_s *pByteStream ); bool SERVER_ProcessCommand( LONG lCommand, BYTESTREAM_s *pByteStream ); diff -r df4ba3bf564e -r a70158861335 src/thingdef/thingdef_codeptr.cpp --- a/src/thingdef/thingdef_codeptr.cpp Wed Nov 04 11:58:06 2020 -0500 +++ b/src/thingdef/thingdef_codeptr.cpp Sat Nov 07 23:42:16 2020 -0500 @@ -453,18 +453,49 @@ if (!looping) { + // [AK] If we're the server, we may need to update the list of looping sound channels. + if ( NETWORK_GetState( ) == NETSTATE_SERVER ) + { + if ( channel & CHAN_LOOP ) + { + // [AK] Only update the sound if it isn't already looping on the same channel. + if ( SERVER_IsChannelLoopingSound( self, channel&7, soundid ) ) + return; + + // [AK] Add or replace the actor's channel to the list of looping sound channels. + if ( SERVER_IsChannelLooping( self, channel&7 ) ) + SERVER_ReplaceLoopingChannel( self, channel, soundid, volume, attenuation ); + else + SERVER_AddLoopingChannel( self, channel, soundid, volume, attenuation ); + } + else + SERVER_RemoveLoopingChannel( self, channel&7 ); + } + S_Sound (self, channel, soundid, volume, attenuation, true ); // [BC] Inform the clients. } else { if (!S_IsActorPlayingSomething (self, channel&7, soundid)) { + // [AK] Only update the sound if it isn't already looping on the same channel. + if ( NETWORK_GetState( ) == NETSTATE_SERVER && SERVER_IsChannelLoopingSound( self, channel&7, soundid ) ) + return; + S_Sound (self, channel | CHAN_LOOP, soundid, volume, attenuation); // [BC] If we're the server, tell clients to play the sound. // [Dusk] We need to respect existing sound play since this is a looped sound. + // [AK] Add or replace the actor's channel to the list of looping sound channels. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) + { SERVERCOMMANDS_SoundActor( self, channel | CHAN_LOOP, S_GetName( soundid ), volume, attenuation, MAXPLAYERS, 0, true ); + + if ( SERVER_IsChannelLooping( self, channel&7 ) ) + SERVER_ReplaceLoopingChannel( self, channel, soundid, volume, attenuation ); + else + SERVER_AddLoopingChannel( self, channel, soundid, volume, attenuation ); + } } } } @@ -475,6 +506,10 @@ ACTION_PARAM_INT(slot, 0); S_StopSound(self, slot); + + // [AK] If we're the server, remove the actor's channel from the list of looping channels. + if ( NETWORK_GetState( ) == NETSTATE_SERVER ) + SERVER_RemoveLoopingChannel( self, slot ); } //========================================================================== @@ -526,17 +561,48 @@ if (!looping) { + // [AK] If we're the server, we may need to update the list of looping sound channels. + if ( NETWORK_GetState( ) == NETSTATE_SERVER ) + { + if ( channel & CHAN_LOOP ) + { + // [AK] Only update the sound if it isn't already looping on the same channel. + if ( SERVER_IsChannelLoopingSound( self, ( int(channel) - NAME_Auto ) & 7, soundid ) ) + return; + + // [AK] Add or replace the actor's channel to the list of looping sound channels. + if ( SERVER_IsChannelLooping( self, ( int(channel) - NAME_Auto ) & 7 ) ) + SERVER_ReplaceLoopingChannel( self, channel, soundid, 1, attenuation ); + else + SERVER_AddLoopingChannel( self, channel, soundid, 1, attenuation ); + } + else + SERVER_RemoveLoopingChannel( self, ( int(channel) - NAME_Auto ) & 7 ); + } + S_Sound (self, int(channel) - NAME_Auto, soundid, 1, attenuation, true ); // [BB] Inform the clients. } else { if (!S_IsActorPlayingSomething (self, int(channel) - NAME_Auto, soundid)) { + // [AK] Only update the sound if it isn't already looping on the same channel. + if ( NETWORK_GetState( ) == NETSTATE_SERVER && SERVER_IsChannelLoopingSound( self, ( int(channel) - NAME_Auto ) & 7, soundid ) ) + return; + S_Sound (self, (int(channel) - NAME_Auto) | CHAN_LOOP, soundid, 1, attenuation); // [BB] If we're the server, tell clients to play the sound, but only if they are not already playing something for this actor. + // [AK] Add or replace the actor's channel to the list of looping sound channels. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) + { SERVERCOMMANDS_SoundActor( self, (int(channel) - NAME_Auto) | CHAN_LOOP, S_GetName( soundid ), 1, attenuation, MAXPLAYERS, 0, true ); + + if ( SERVER_IsChannelLooping( self, ( int(channel) - NAME_Auto ) & 7 ) ) + SERVER_ReplaceLoopingChannel( self, int(channel) - NAME_Auto, soundid, 1, attenuation ); + else + SERVER_AddLoopingChannel( self, int(channel) - NAME_Auto, soundid, 1, attenuation ); + } } } } @@ -549,6 +615,10 @@ if (channel > NAME_Auto && channel <= NAME_SoundSlot7) { S_StopSound (self, int(channel) - NAME_Auto); + + // [AK] If we're the server, remove the actor's channel from the list of looping channels. + if ( NETWORK_GetState() == NETSTATE_SERVER ) + SERVER_RemoveLoopingChannel( self, int(channel) - NAME_Auto ); } }