FWGS / xash3d-fwgs

Xash3D FWGS engine.
1.54k stars 233 forks source link

Playing sentence on the same channel of the same entity may lead to playing both sounds in parallel #1196

Closed FreeSlave closed 3 months ago

FreeSlave commented 1 year ago

I have the entity that creates the entity singletone which plays a sound either in world or on player by attaching itself to the player.

// add somewhere, e.g. in sound.cpp

#define SF_AMBIENT_RADIO_NOT_ON_PLAYER 1

class CAmbientRadio : public CPointEntity
{
public:
    void Spawn();
    void Precache();
    void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value);
};

LINK_ENTITY_TO_CLASS( ambient_radio, CAmbientRadio )

void CAmbientRadio::Spawn()
{
    CPointEntity::Spawn();
    Precache();
}

void CAmbientRadio::Precache()
{
    PRECACHE_MODEL("sprites/iunknown.spr");
    //PRECACHE_SOUND(STRING(pev->message));
}

void CAmbientRadio::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value)
{
    edict_t* pPlayer = g_engfuncs.pfnPEntityOfEntIndex( 1 );

    if (!pPlayer) {
        ALERT(at_console, "Could not find a player to play a radio message on!\n");
        return;
    }

    const char *szSoundFile = STRING( pev->message );

    CBaseEntity* pRadioEnt = UTIL_FindEntityByTargetname(0, "__player_radio");
    if (!pRadioEnt) {
        edict_t *pent;

        pent = CREATE_NAMED_ENTITY( MAKE_STRING( "info_target" ) );
        if( FNullEnt( pent ) )
        {
            ALERT ( at_console, "NULL info_target!\n" );
            return;
        }
        pRadioEnt = Instance( pent );
        pRadioEnt->pev->origin = pPlayer->v.origin;
        pRadioEnt->pev->angles = pPlayer->v.angles;

        if (pRadioEnt) {
            ALERT(at_console, "Created radio info_target\n");
            pRadioEnt->pev->targetname = MAKE_STRING("__player_radio");
            pRadioEnt->pev->movetype = MOVETYPE_FOLLOW;
            pRadioEnt->pev->aiment = pPlayer;
            DispatchSpawn(pRadioEnt->edict());
            SET_MODEL( pRadioEnt->edict(), "sprites/iunknown.spr" );
            pRadioEnt->pev->rendermode = kRenderTransAlpha;
        }
    }

    if (pRadioEnt) {
        float attenuation = ATTN_NORM;
        if (FBitSet(pev->spawnflags, SF_AMBIENT_RADIO_NOT_ON_PLAYER)) {
            pRadioEnt->pev->movetype = MOVETYPE_NONE;
            pRadioEnt->pev->aiment = 0;
            UTIL_SetOrigin(pRadioEnt->pev, pev->origin);
        } else {
            pRadioEnt->pev->movetype = MOVETYPE_FOLLOW;
            pRadioEnt->pev->aiment = pPlayer;
            attenuation = ATTN_NONE;
        }

        EMIT_SOUND( pRadioEnt->edict(), CHAN_VOICE, szSoundFile, 1.0f, attenuation);
    }
}

The point is to override any sentence which is currently played on CHAN_VOICE on triggering other ambient_radio. This way we should ensure that two sentences don't play in parallel, and it works this way in GoldSource.

However it doesn't work as expected in Xash3D, at least when one ambient_radio plays a sentence in world, and other one plays another sentence on the player. Instead both are playing in parallel.

Here's the test map: radiotest.bsp.zip. Push two buttons to reproduce the bug.

Field Intensity mod is affected by the bug when playing on Xash3D, on the map fid1a0a. Pickup the radio right after the radioman plays its sentence and you'll hear his next sentence playing in parallel to the previous one.

a1batross commented 1 year ago

We probably need that mixer rewrite I planned a while ago.

a1batross commented 3 months ago

Turns out, it isn't a mixer error, but yet another undocumented Xash extension.

In SV_BuildSoundMsg, there is a check:

    if( SV_IsValidEdict( ent ) && SV_IsValidEdict( ent->v.aiment ))
        entityIndex = NUM_FOR_EDICT( ent->v.aiment );
    else if( SV_IsValidEdict( ent ))
        entityIndex = NUM_FOR_EDICT( ent );
    else entityIndex = 0; // assume world

When an entity has an aiment set, the sound is automatically gets attached to that entity.

I think this check is kinda stupid, if a game developer explicitly passed an edict to EmitSound, then they might actually want to play sound from that entity, not from whatever was set in the aiment.

This check was added more than 10 years ago: https://github.com/FWGS/Xash3DArchive/commit/8f6f3fc351d1ff55e718643174e30e477e0eb5d0. Judging by changelog entry, it was made to fix the sound problem with weapons. I'm pretty sure this is an outdated check and can be safely reverted.

a1batross commented 3 months ago

080eba948fa8cb5a26278529a939c6c82a1a9412