Skip to content

Mod Integration Gate

artriy edited this page Jul 17, 2026 · 5 revisions

Gate: Mute

The Gate primitive can silence a living player's voice in Tasks, Meeting, or Exile. It covers role behaviors such as "mute this player while a modifier is active" and "mute living speakers while a system effect is active."

API 1.1 exposes a per-speaker Muffle verdict, but does not currently route that verdict to an audible filter. Use one of the working muffle alternatives instead.

Back to Mod Integration


Per-player rule

Register a cheap callback that is evaluated for each player at voice-snapshot cadence, about 20 times per second:

PerfectCommsApi.RegisterVoiceRule("com.me.mymod", ctx =>
{
    // Gate mute is currently enforced only for living speakers in
    // Tasks, Meeting, and Exile.
    if (ctx.IsDead)
        return VoiceRuleResult.Pass;

    if (ctx.Phase == VoicePhaseKind.Meeting &&
        MyRoles.IsGagged(ctx.Player))
    {
        return VoiceRuleResult.Mute("Gagged");
    }

    return VoiceRuleResult.Pass;
});

Verdicts and precedence

Verdict API 1.1 behavior
VoiceRuleResult.Mute(reason) The living speaker is silenced in a supported phase. The reason is available to the local transmit-block status.
VoiceRuleResult.Pass No opinion; built-in rules and other integrations continue to decide.
VoiceRuleResult.Muffle(reason) Recorded, but its per-speaker low-pass effect is not currently routed. Do not depend on it.

Rules are evaluated in registration order. A Muffle result does not stop evaluation, and any later Mute overrides it. The first Mute encountered ends rule evaluation and supplies the mute reason. Return Pass whenever your role does not apply.


Global gate

For a synchronized effect that mutes every living speaker in one supported phase, register a phase-scoped global gate:

PerfectCommsApi.RegisterGlobalGate(
    "com.me.mymod",
    VoicePhaseKind.Tasks,
    () => MySystems.IsJamActive,
    "Jammed");

The predicate is called as voice state is evaluated, so keep it cheap and throw-free. Register separate gates for each phase you support:

PerfectCommsApi.RegisterGlobalGate(
    "com.me.mymod",
    VoicePhaseKind.Meeting,
    () => MySystems.IsJamActive,
    "Jammed");

PerfectCommsApi.RegisterGlobalGate(
    "com.me.mymod",
    VoicePhaseKind.Exile,
    () => MySystems.IsJamActive,
    "Jammed");

Registering a Meeting gate does not also register an Exile gate; they are distinct API phase values.


Runtime boundaries

  • Supported speakers and phases: Gate mute is enforced for living speakers in Tasks, Meeting, and Exile.
  • Unsupported boundaries: Gate mute is not enforced in Lobby or for dead speakers, even though callbacks can observe those context values.
  • The local microphone is gated too: when a supported rule mutes the living local player, Perfect Comms blocks their transmit path.
  • Audio failures are neutral: a throwing global predicate is treated as inactive; a throwing per-player rule is treated as Pass. The rest of the voice frame continues.
  • Evaluation is local, not synchronization: clients agree only when your mod has already synchronized the relevant role/effect state and each client runs compatible integration code.
  • Built-in rules still apply: Pass never bypasses Perfect Comms' normal routing or another mod's restriction.

Working muffle alternatives

Muffle everything the local listener hears

RegisterListenerFilter applies the working listener low-pass filter to all incoming audio for the local player:

PerfectCommsApi.RegisterListenerFilter("com.me.mymod", local =>
    MyRoles.ShouldHearMuffledAudio(local));

This is listener-wide, not per-speaker. The callback receives only the local PlayerControl, so it cannot read host options through a VoiceRuleContext.

Muffle a matching private channel

A custom channel can use the working channel filter:

return new VoiceChannelResult(
    "cursed-radio",
    TwoWay: true,
    Shape: VoiceAudioShape.Muffle);

Only players who resolve the same namespaced channel key receive that route. See Channels for membership and routing rules.


Patterns

Mute a living player during Tasks while a modifier is present:

PerfectCommsApi.RegisterVoiceRule("com.me.mymod", ctx =>
    ctx.Phase == VoicePhaseKind.Tasks &&
    !ctx.IsDead &&
    ctx.Player.GetModifier<SilencedModifier>() != null
        ? VoiceRuleResult.Mute("Silenced")
        : VoiceRuleResult.Pass);

Mute only the living local player during a Meeting:

PerfectCommsApi.RegisterVoiceRule("com.me.mymod", ctx =>
    ctx.Phase == VoicePhaseKind.Meeting &&
    ctx.IsLocal &&
    !ctx.IsDead &&
    MyState.SelfMuted
        ? VoiceRuleResult.Mute("Muted")
        : VoiceRuleResult.Pass);

Gate behind a host option (see Host Options):

PerfectCommsApi.RegisterVoiceRule("com.me.mymod", ctx =>
    ctx.Phase == VoicePhaseKind.Meeting &&
    !ctx.IsDead &&
    ctx.GetOption("MuteSilenced") &&
    MyRoles.IsSilenced(ctx.Player)
        ? VoiceRuleResult.Mute("Silenced")
        : VoiceRuleResult.Pass);

Next

Clone this wiki locally