-
Notifications
You must be signed in to change notification settings - Fork 3
Mod Integration Channels
A channel lets players who resolve the same channel key hear one another outside the ordinary proximity route. API 1.1 supports flat radio audio, flat muffled audio, and task-phase spatial audio from an explicit world position.
← Back to Mod Integration
Register a callback that returns one channel membership for the player being evaluated, or null when the player is not on a channel:
PerfectCommsApi.RegisterVoiceChannel("com.me.mymod", ctx =>
{
byte team = MyRoles.TeamOf(ctx.Player);
return team != byte.MaxValue
? new VoiceChannelResult($"team:{team}")
: null;
});VoiceRuleContext supplies the player, phase, local/dead flags, and access to this mod's host-synced options. The key must be non-empty. Perfect Comms namespaces it by modId, so only players whose resolver returns the same key for the same mod can share the route.
Return null whenever the rule does not apply. A non-null result with an empty key is ignored and can prevent a later resolver registered under the same mod id from being considered.
new VoiceChannelResult(
Key, // required, non-empty
TwoWay: true, // keep true in API 1.1
Shape: VoiceAudioShape.Radio,
Volume: 1f, // clamped to 0..1
Origin: null);Perfect Comms accepts the first non-null, non-empty channel membership for a player. Within one mod id, callbacks are checked in registration order. Avoid depending on order between different mods; register one resolver per mod and decide its channel internally.
| Shape | Current API 1.1 behavior |
|---|---|
Radio |
Flat, unfiltered audio with no distance falloff. This is the default. |
Muffle |
Flat audio through the listener-muffle low-pass filter. |
Proximity |
Spatial falloff only when Origin is explicitly supplied and a task-phase listener position is available. |
Volume is clamped to 0f..1f before routing.
For working spatial audio, use Shape: VoiceAudioShape.Proximity and provide an explicit Origin:
PerfectCommsApi.RegisterVoiceChannel("com.me.mymod", ctx =>
MyRoles.SeancePoint(ctx.Player) is Vector2 spirit
? new VoiceChannelResult(
"seance",
Shape: VoiceAudioShape.Proximity,
Origin: spirit)
: null);During tasks, the target is heard from Origin with the host's distance/falloff settings. A Proximity result without Origin is currently flat audio, not speaker-body proximity. Meetings do not provide a spatial listener position, so Proximity channels also fall back to flat audio there.
Leave TwoWay at true. Although the public record contains TwoWay, setting it to false does not provide a reliable one-directional route in API 1.1. Do not build role behavior around TwoWay: false.
Faction radio:
PerfectCommsApi.RegisterVoiceChannel("com.me.mymod", ctx =>
MyRoles.IsCultist(ctx.Player)
? new VoiceChannelResult("cult")
: null);Private pair:
PerfectCommsApi.RegisterVoiceChannel("com.me.mymod", ctx =>
{
byte ownerId = MyRoles.LinkOwnerOf(ctx.Player);
return ownerId != byte.MaxValue
? new VoiceChannelResult($"link:{ownerId}")
: null;
});Host-configurable channel:
PerfectCommsApi.RegisterVoiceChannel("com.me.mymod", ctx =>
ctx.GetOption("CultRadio") && MyRoles.IsCultist(ctx.Player)
? new VoiceChannelResult("cult")
: null);- A living speaker muted during Tasks/Meeting/Exile by a built-in rule or
VoiceRuleResult.Mute(...)stays muted; a channel does not bypass that mute. API 1.1 gate mute is not enforced for dead speakers or Lobby voice. - Mod channels are checked in meetings and tasks before built-in team radio.
- Channel state is evaluated locally from your mod's state. Perfect Comms does not synchronize role or membership state for you.
- A throwing callback is treated as
nullfor that evaluation. - Register once and call
PerfectCommsApi.Unregister(modId)from your unload path. Duplicate registrations accumulate.
- Listener Origin — relocate where the local player hears from.
- Host Options & Tabs — gate a channel behind a host toggle.
- API Reference — complete API 1.1 signatures and limitations.