PlayerVoiceChat.cs
using Sandbox;
using System;
namespace PaintballBaddies;
/// <summary>Local preferences around the engine's owner-controlled voice transmitter.</summary>
public sealed class PlayerVoiceChat : Component
{
public const string PreferenceKey="paintball-voice-chat-enabled";
public static bool ChatEnabled => Game.Cookies.Get(PreferenceKey,true);
public static void Toggle() => Game.Cookies.Set(PreferenceKey,!ChatEnabled);
public static bool HoldToTalk => Game.Cookies.Get("paintball-voice-hold-to-talk",false);
public static void ToggleMode() => Game.Cookies.Set("paintball-voice-hold-to-talk",!HoldToTalk);
public bool MicOpen {get;private set;}
private bool previousHoldMode;
private IDisposable inputHook;
public Voice Transmitter => Components.Get<Voice>();
public bool Talking => Transmitter is {} voice && (IsProxy
? voice.LastPlayed<.3f && voice.Amplitude>.001f
: voice.IsListening);
protected override void OnUpdate()
{
var voice=Transmitter;
if(!voice.IsValid())return;
// The native Voice component handles ownership, transport and the Voice mixer.
// Lobby-wide playback keeps conversation intelligible across the entire arena.
voice.Volume=ChatEnabled ? .85f : 0;
}
protected override void OnStart()
{
previousHoldMode=HoldToTalk;
inputHook=Scene.AddHook(GameObjectSystem.Stage.StartUpdate,-20,UpdateMicrophone,
nameof(PlayerVoiceChat),"Apply microphone gate before native voice recording");
}
private void UpdateMicrophone()
{
if(IsProxy)return;
var voice=Transmitter;if(!voice.IsValid())return;
bool allowed=MultiplayerSession.Online && ChatEnabled
&& Scene.GetAllComponents<PaintballControls>().FirstOrDefault()?.Open!=true;
if(!allowed || previousHoldMode!=HoldToTalk)MicOpen=false;
previousHoldMode=HoldToTalk;
if(allowed && !HoldToTalk && Input.Pressed("voice"))MicOpen=!MicOpen;
bool transmit=allowed && (HoldToTalk ? Input.Down("voice") : MicOpen);
// Gate both native preference paths: global PTT reads its named action,
// while global open-mic uses the Manual listening flag.
voice.Mode=Voice.ActivateMode.Manual;
voice.PushToTalkInput="voicetransmit";
Input.SetAction("voicetransmit",transmit);
voice.IsListening=transmit;
}
protected override void OnDestroy()
{
inputHook?.Dispose();
if(IsProxy)return;
Input.SetAction("voicetransmit",false);
if(Transmitter.IsValid())Transmitter.IsListening=false;
}
}