Skip to content

Mod Integration Host Options

artriy edited this page Jul 17, 2026 · 5 revisions

Host Options & Tabs

Host options give a mod session-local toggles and enum steppers in the Perfect Comms host panel. Their current values travel with the host-settings snapshot so callbacks on clients that registered the same option can read the host's selection.

← Back to Mod Integration


Declare options

Register options once after confirming Perfect Comms is loaded:

const string Mod = "com.me.mymod";

PerfectCommsApi.RegisterHostOption(
    Mod,
    new VoiceHostOption(
        Key: "MuteSilenced",
        Label: "<b>Silencer</b>: Mute Silenced",
        Default: true)
    {
        Description = "Prevents silenced players from transmitting voice."
    });

PerfectCommsApi.RegisterHostEnumOption(
    Mod,
    new VoiceHostEnumOption(
        Key: "GhostVoice",
        Label: "<b>Spirit</b>: Ghost Voice",
        Default: 0,
        Choices: new[] { "Off", "Both" })
    {
        Description = "Enables a two-way spirit channel."
    });

Description becomes the option's in-game help text. Label supports the rich-text markup used by the built-in host settings.

Caller validation requirements

API 1.1 silently ignores an empty modId or null option, but it does not otherwise validate option declarations. The integrating mod must ensure:

  • modId is a stable, case-sensitive reverse-DNS id;
  • Key is non-empty, stable, case-sensitive, and simple (avoid . and control characters);
  • option keys are unique within the mod;
  • enum Choices is non-null and non-empty;
  • enum Default is in 0..Choices.Length - 1;
  • callbacks handle an unexpected enum integer safely when clients have mismatched versions.

Duplicate option registrations are not deduplicated. They create duplicate rows while sharing the first value registered for the composed key. Register once.


Read values

VoiceRuleContext, VoiceOverlayViewerContext, and VoiceOverlaySpeakerContext expose accessors for options registered under the same modId as the callback:

PerfectCommsApi.RegisterVoiceRule(Mod, ctx =>
    ctx.GetOption("MuteSilenced") && MyRoles.IsSilenced(ctx.Player)
        ? VoiceRuleResult.Mute("Silenced")
        : VoiceRuleResult.Pass);

PerfectCommsApi.RegisterVoiceChannel(Mod, ctx =>
    ctx.GetEnumOption("GhostVoice") != 0 && MyRoles.IsSpirit(ctx.Player)
        ? new VoiceChannelResult("spirit")
        : null);

Pass the bare option key. Perfect Comms composes it as modId.Key for local storage and synchronization.

Listener-origin and listener-filter callbacks receive only PlayerControl; they do not have option accessors. Resolve any controlling option state elsewhere in your integration before those callbacks read it.


Add one mod tab

PerfectCommsApi.RegisterModTab(Mod, "My Mod");

Options render only when the same modId also has a tab. One tab is supported per exact modId; the first registration fixes its label and later RegisterModTab calls for that id are ignored.

Tabs appear in tab-registration order beneath MOD BEHAVIOUR. Inside a tab, all toggles render first in toggle-registration order, followed by all enums in enum-registration order. A client without the mod does not register or render its tab.


Value lifetime and synchronization

  • Values are session-local memory owned by Perfect Comms. They are not written to the mod's or Perfect Comms' BepInEx configuration and reset to registered defaults after restart/re-registration.
  • Only option values are synchronized. Tab labels, option labels, choices, descriptions, and callback state are local declarations; clients need compatible mod/API registrations for matching behavior.
  • Unknown option hashes on a client are ignored. A client without the option keeps no callback-visible value for it.
  • The host-settings snapshot supports at most 256 synchronized mod options total across all installed mods. Exceeding that limit prevents the settings snapshot from being sent.

Key and trust limitations

The wire block identifies each option with a 32-bit hash of modId.Key. It is offset-independent, but it is not collision-proof. Stable reverse-DNS ids and simple unique keys reduce accidental ambiguity; API 1.1 does not detect hash collisions.

Host-object matching on the settings RPC is a lobby-compatibility check, not hostile-client authentication. Host options are appropriate for cooperative lobby policy, not security-sensitive authorization. Do not claim that a modified client is unable to forge or ignore values.


Registration lifecycle

All registration methods except RegisterModTab accumulate duplicates. If an integration can be initialized more than once, guard it or call:

PerfectCommsApi.Unregister(Mod);

before registering again. Unregister(modId) removes every callback, gate, channel, origin, filter, overlay rule, tab, option declaration, local value, and remote default/value for that id. API 1.1 has no per-option or per-callback unregister method.


Next

Clone this wiki locally