Pepper.SFX

Features

Multiplayer

Post a sound once and every player hears it, with the same random picks on every machine and running loops replayed to late joiners.

Full version Only in the full version of Pepper.SFX.

A door one player opens should be heard by everyone, a footstep should pick the same variation on every machine, and an alarm already sounding should reach whoever joins later. Pepper.SFX’s netcode layer sends a short description of each sound, never the audio, and every machine plays it through its own Audio Manager.

How it works

  • A core that needs no netcode package. SFXSystem.Netcode references only Pepper’s runtime. A small adapter per networking package (FishNetAudioTransport, NgoAudioTransport) is the only code that touches it, and compiles only when that package is installed.
  • Intent, not audio. A post sends about 36 bytes: the event, the position, an object to follow and a random seed. Each machine plays it locally, so occlusion, reverb and voice management work as in single player.
  • Local echo. PostNetworkedEvent plays at once for the player who caused it; the server relays it to the others. With no session it is a plain local post.
  • Stable event IDs. Each Audio Event has a Stable ID worked out from its asset GUID, so every machine resolves it to the same event.
  • Seed parity. By default a networked post makes the same random picks everywhere: the clip, the pitch and volume randomisation, a Sequence’s later clips. Pass independentVariation: true for sounds such as a crowd.
  • Late join. PostNetworkedLoop returns a handle, and StopNetworked stops the loop everywhere. The server replays running loops to a player who joins later. The event’s Loop Sync Tier sets the joiner’s phase: 0 from the start, 1 aligned at join, 2 phase-locked (experimental).
  • Server-authored sounds. PostServerEvent and PostServerLoop for sounds the server decides, such as a round start.
  • Proximity culling. With culling on, the server sends a 3D sound only to clients within its audible range, which also closes an audio wallhack. 2D sounds are never culled.
  • Leaving it out. The SFXSYSTEM_DISABLE_NETCODE define leaves every multiplayer assembly out of your build.

Example

using AudioSystem;
using AudioSystem.Netcode;
using UnityEngine;

// On a door that has a NetworkObject.
public class DoorAudio : MonoBehaviour
{
    private NetworkedSoundHandle alarm;

    public void Open()
    {
        // Plays here now; the server relays it to the other players, attached to this door.
        NetworkedAudioManager.PostNetworkedEvent("door_open", transform.position, gameObject);
    }

    public void StartAlarm()
    {
        // A shared loop: players who join later hear it too.
        alarm = NetworkedAudioManager.PostNetworkedLoop("alarm_loop", transform.position, gameObject);
    }

    public void StopAlarm()
    {
        NetworkedAudioManager.StopNetworked(alarm);   // stops it on every machine
        alarm = null;
    }
}

The door sound plays at once for the player who opened it and follows the door on the other machines. Passing the alarm’s handle to StopNetworked ends the loop for everyone.

Setting it up

  1. Install one networking package: FishNet v4 or Netcode for GameObjects 2.x. The matching adapter compiles by itself.
  2. Open Window > Audio System > Audio Event IDs and click Capture All Missing IDs.
  3. Make one persistent networked GameObject with a NetworkObject and FishNetAudioTransport or NgoAudioTransport: one per session, active in the scene, not on player objects.
  4. Optionally add a NetworkAudioSettings component for proximity culling, and assign its ListenerPositionProvider from code.
  5. Set Unreliable Delivery, Independent Variation and Loop Sync Tier in each Audio Event’s Multiplayer foldout.
  6. In Play mode, Window > Audio System > Network Audio Debug shows the session, clock and loops.

Good to know

  • Support: FishNet v4 is the tested backend, on one PC and on two over a real network. Netcode for GameObjects 2.x compiles but is only lightly tested. NGO 1.x and FishNet v3 cause compile errors. Mirror is not supported.
  • Loop Sync Tier 2 is experimental: a late joiner may hear the loop out of sync for a cycle or two before it locks in.
  • Proximity culling can use the wrong range for events that play a Switch or Blend container, so a nearby player might miss the sound.
  • RTPCs, switches, states and ducking aren’t replicated; each client’s game logic drives them.
  • Built for co-op and competitive sessions of up to tens of players.
  • On a dedicated server, set AudioManager.Inert = true at boot so it plays nothing but can still relay.

Learn more